mirror of
https://github.com/esuo1198/TaikoArcadeLoader.git
synced 2026-10-07 06:08:05 +03:00
Merge pull request #26 from ryumiyax/experimental
[Experimental] config Refactor | log Optimize & Banner & Version | Simple Input
This commit is contained in:
+125
-59
@@ -7,6 +7,20 @@ if(MSVC)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE INTERNAL "")
|
||||
endif()
|
||||
|
||||
find_package(Git REQUIRED)
|
||||
|
||||
# Commands to read each needed variable
|
||||
set(variablesToRead "GIT_BRANCH;GIT_SHA1;GIT_SHORTSHA1;GIT_DIRTY")
|
||||
set(CMD_GIT_VERSION ${GIT_EXECUTABLE} describe --tags --dirty)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMD_GIT_VERSION}
|
||||
RESULT_VARIABLE GIT_VERSION_RESULT
|
||||
OUTPUT_VARIABLE GIT_VERSION
|
||||
ERROR_VARIABLE GIT_ERROR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Set C and C++ standards
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -24,24 +38,13 @@ endif()
|
||||
|
||||
# Add project definitions (Add ASYNC_UPDATE/ASYNC_IO to enable new async feature [experimental])
|
||||
# add_definitions(-DNOMINMAX -DLTC_NO_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS -DASYNC_UPDATE)
|
||||
add_definitions(-DNOMINMAX -DLTC_NO_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DNOMINMAX -DLTC_NO_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS -DTAL_VERSION="${GIT_VERSION}")
|
||||
MESSAGE( STATUS "Build Version = ${GIT_VERSION}.")
|
||||
|
||||
|
||||
# Include FetchContent module
|
||||
include(FetchContent)
|
||||
|
||||
# Fetch tomlc99 (no built-in CMake support)
|
||||
FetchContent_Declare(
|
||||
tomlc99
|
||||
GIT_REPOSITORY https://github.com/cktan/tomlc99.git
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_GetProperties(tomlc99)
|
||||
if(NOT tomlc99_POPULATED)
|
||||
FetchContent_MakeAvailable(tomlc99)
|
||||
add_library(tomlc99 STATIC ${tomlc99_SOURCE_DIR}/toml.c)
|
||||
target_include_directories(tomlc99 PUBLIC ${tomlc99_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
# Fetch stb (header-only library, no built-in CMake support)
|
||||
FetchContent_Declare(
|
||||
stb
|
||||
@@ -130,48 +133,94 @@ FetchContent_Declare(
|
||||
)
|
||||
FetchContent_MakeAvailable(minhook)
|
||||
|
||||
FetchContent_Declare(
|
||||
tomlplusplus
|
||||
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
|
||||
GIT_TAG v3.4.0
|
||||
)
|
||||
FetchContent_MakeAvailable(tomlplusplus)
|
||||
export(TARGETS tomlplusplus_tomlplusplus FILE "${CMAKE_BINARY_DIR}/tomlplusplus-config.cmake")
|
||||
set(tomlplusplus_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
FetchContent_Declare(
|
||||
reflectcpp
|
||||
URL https://github.com/getml/reflect-cpp/archive/refs/tags/v0.17.0.zip
|
||||
)
|
||||
set(REFLECTCPP_TOML ON CACHE BOOL "" FORCE)
|
||||
set(REFLECTCPP_XML OFF CACHE BOOL "" FORCE)
|
||||
set(REFLECTCPP_USE_VCPKG OFF CACHE BOOL "" FORCE)
|
||||
FetchContent_MakeAvailable(reflectcpp)
|
||||
|
||||
# Source files
|
||||
set(SOURCES
|
||||
src/dllmain.cpp
|
||||
src/helpers.cpp
|
||||
src/logger.cpp
|
||||
src/poll.cpp
|
||||
src/pollasync.cpp
|
||||
src/bnusio.cpp
|
||||
src/Windows/WindowsError.cpp
|
||||
src/Windows/MinimumLatencyAudioClient.cpp
|
||||
src/patches/amauth.cpp
|
||||
# src/patches/dxgi.cpp
|
||||
# src/patches/fpslimiter.cpp
|
||||
src/patches/audio.cpp
|
||||
src/patches/plugins.cpp
|
||||
src/patches/scanner.cpp
|
||||
src/patches/layeredfs.cpp
|
||||
src/patches/testmode.cpp
|
||||
src/patches/timer.cpp
|
||||
src/patches/language.cpp
|
||||
# src/patches/unlimitsong.cpp
|
||||
src/patches/versions/JPN00.cpp
|
||||
src/patches/versions/JPN08.cpp
|
||||
src/patches/versions/JPN39.cpp
|
||||
src/patches/versions/CHN00.cpp
|
||||
src/dllmain.cpp
|
||||
src/helpers.cpp
|
||||
src/logger.cpp
|
||||
src/poll.cpp
|
||||
src/pollasync.cpp
|
||||
src/bnusio.cpp
|
||||
src/Windows/WindowsError.cpp
|
||||
src/Windows/MinimumLatencyAudioClient.cpp
|
||||
src/patches/amauth.cpp
|
||||
# src/patches/dxgi.cpp
|
||||
# src/patches/fpslimiter.cpp
|
||||
src/patches/audio.cpp
|
||||
src/patches/plugins.cpp
|
||||
src/patches/scanner.cpp
|
||||
src/patches/layeredfs.cpp
|
||||
src/patches/testmode.cpp
|
||||
src/patches/timer.cpp
|
||||
src/patches/language.cpp
|
||||
# src/patches/unlimitsong.cpp
|
||||
src/patches/versions/JPN00.cpp
|
||||
src/patches/versions/JPN08.cpp
|
||||
src/patches/versions/JPN39.cpp
|
||||
src/patches/versions/CHN00.cpp
|
||||
src/config.cpp
|
||||
src/banner.cpp
|
||||
)
|
||||
|
||||
set(VALIDATOR_SOURCES
|
||||
src/configValidator.cpp
|
||||
src/helpers.cpp
|
||||
src/config.cpp
|
||||
src/logger.cpp
|
||||
)
|
||||
|
||||
# Create the library
|
||||
add_library(bnusio SHARED ${SOURCES})
|
||||
add_executable(validator ${VALIDATOR_SOURCES})
|
||||
|
||||
# Remove 'lib' prefix from the library name, make sure the output directory is expected
|
||||
set_target_properties(bnusio PROPERTIES
|
||||
PREFIX ""
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>")
|
||||
|
||||
set_target_properties(validator PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>"
|
||||
)
|
||||
|
||||
# Remove 'lib' prefix from the library name
|
||||
set_target_properties(bnusio PROPERTIES PREFIX "")
|
||||
|
||||
# Include directories
|
||||
target_include_directories(bnusio PRIVATE
|
||||
src
|
||||
${tomlc99_SOURCE_DIR}
|
||||
${SDL3_SOURCE_DIR}/include
|
||||
${xxhash_SOURCE_DIR}
|
||||
${zlib_SOURCE_DIR}
|
||||
${libtomcrypt_SOURCE_DIR}/src/headers
|
||||
${minhook_SOURCE_DIR}/include
|
||||
src
|
||||
${SDL3_SOURCE_DIR}/include
|
||||
${xxhash_SOURCE_DIR}
|
||||
${zlib_SOURCE_DIR}
|
||||
${libtomcrypt_SOURCE_DIR}/src/headers
|
||||
${minhook_SOURCE_DIR}/include
|
||||
${reflectcpp_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_include_directories(validator PRIVATE
|
||||
src
|
||||
${SDL3_SOURCE_DIR}/include
|
||||
${xxhash_SOURCE_DIR}
|
||||
${zlib_SOURCE_DIR}
|
||||
${libtomcrypt_SOURCE_DIR}/src/headers
|
||||
${minhook_SOURCE_DIR}/include
|
||||
${reflectcpp_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
# Compiler definitions
|
||||
@@ -186,18 +235,35 @@ endif()
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(bnusio PRIVATE
|
||||
tomlc99
|
||||
SDL3-static
|
||||
xxhash
|
||||
zlibstatic
|
||||
libtomcrypt
|
||||
safetyhook
|
||||
ZXing::ZXing
|
||||
pugixml
|
||||
stb
|
||||
ws2_32
|
||||
ntdll
|
||||
minhook
|
||||
SDL3-static
|
||||
xxhash
|
||||
zlibstatic
|
||||
libtomcrypt
|
||||
safetyhook
|
||||
ZXing::ZXing
|
||||
pugixml
|
||||
stb
|
||||
ws2_32
|
||||
ntdll
|
||||
minhook
|
||||
tomlplusplus::tomlplusplus
|
||||
reflectcpp
|
||||
)
|
||||
|
||||
target_link_libraries(validator PRIVATE
|
||||
SDL3-static
|
||||
xxhash
|
||||
zlibstatic
|
||||
libtomcrypt
|
||||
safetyhook
|
||||
ZXing::ZXing
|
||||
pugixml
|
||||
stb
|
||||
ws2_32
|
||||
ntdll
|
||||
minhook
|
||||
tomlplusplus::tomlplusplus
|
||||
reflectcpp
|
||||
)
|
||||
|
||||
# Define log path; used to make the file path relative in the log calls.
|
||||
@@ -220,7 +286,7 @@ endif()
|
||||
add_custom_command(
|
||||
TARGET bnusio POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/bnusio.dll"
|
||||
"${CMAKE_BINARY_DIR}/$<CONFIG>/bnusio.dll"
|
||||
"${CMAKE_SOURCE_DIR}/dist/bnusio.dll"
|
||||
COMMENT "Copying bnusio.dll to dist directory"
|
||||
)
|
||||
|
||||
@@ -34,12 +34,8 @@ version = "auto" # Patch version
|
||||
# | - JPN08: For use with Taiko JPN 08.18
|
||||
# | - JPN39: For use with Taiko JPN 39.06
|
||||
# | - CHN00: For use with Taiko CHN 00.32
|
||||
<<<<<<< HEAD
|
||||
unlock_songs = true # Self-explanatory
|
||||
local_files = true # Only set this to false if you're using this on a Nijiiro Cabinet, running on BNA1
|
||||
=======
|
||||
unlock_songs = true
|
||||
>>>>>>> 684ee61 (Several fix & optimize)
|
||||
|
||||
[patches.chn00] # These patches are only available for version CHN00
|
||||
fix_language = false # Sync test mode language to attract etc
|
||||
@@ -92,7 +88,7 @@ song_no = [] # Song noes used for custom folder
|
||||
wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0)
|
||||
analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets)
|
||||
global_keyboard = false # Accept keyboard input even if Taiko.exe is not foreground
|
||||
|
||||
simple_input = false # Simplified input handler, might decrease game laggy
|
||||
|
||||
|
||||
[keyboard]
|
||||
@@ -105,6 +101,7 @@ enabled = false # Replace assets from the game using a layered file
|
||||
# | For example if you want to edit the wordlist, add your edited version like so:
|
||||
# | .\Data_mods\x64\datatable\wordlist.json
|
||||
# | You can provide both unencrypted and encrypted files.
|
||||
mod_dir = "Data_mods"
|
||||
|
||||
|
||||
[logging]
|
||||
@@ -112,12 +109,14 @@ log_level = "INFO" # Log level, Can be either "NONE", "ERROR", "WARN",
|
||||
# | Keep this as low as possible (Info is usually more than enough) as more logging will slow down your game
|
||||
log_to_file = false # Log to file, set this to true to save the logs from your last session to TaikoArcadeLoader.log
|
||||
# |Again, if you do not have a use for this (debugging mods or whatnot), turn it off.
|
||||
log_path = "logs.log" # Log file path (Can be both relative and absolute).
|
||||
log_method_name = true
|
||||
log_full_source = true
|
||||
log_dir = "./logs/" # Log file path (Can be both relative and absolute).
|
||||
```
|
||||
|
||||
### TestMode options (JPN39 only)
|
||||
|
||||
TaikoArcadeLoader offers several patches to select in TestMode
|
||||
TaikoArcadeLoader offers several patches to select in TestMode
|
||||
|
||||
The follow options are available in "MOD MANAGER" menu:
|
||||
|
||||
|
||||
Vendored
+5
-1
@@ -67,6 +67,7 @@ song_no = [] # Song noes used for custom folder
|
||||
wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0)
|
||||
analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets)
|
||||
global_keyboard = false # Accept keyboard input even if Taiko.exe is not foreground
|
||||
simple_input = false # Simplified input handler, might decrease game laggy
|
||||
|
||||
|
||||
[keyboard]
|
||||
@@ -79,6 +80,7 @@ enabled = false # Replace assets from the game using a layered file
|
||||
# | For example if you want to edit the wordlist, add your edited version like so:
|
||||
# | .\Data_mods\x64\datatable\wordlist.json
|
||||
# | You can provide both unencrypted and encrypted files.
|
||||
mod_dir = "Data_mods"
|
||||
|
||||
|
||||
[logging]
|
||||
@@ -86,4 +88,6 @@ log_level = "INFO" # Log level, Can be either "NONE", "ERROR", "WARN",
|
||||
# | Keep this as low as possible (Info is usually more than enough) as more logging will slow down your game
|
||||
log_to_file = false # Log to file, set this to true to save the logs from your last session to TaikoArcadeLoader.log
|
||||
# |Again, if you do not have a use for this (debugging mods or whatnot), turn it off.
|
||||
log_path = "logs.log" # Log file path (Can be both relative and absolute).
|
||||
log_method_name = true
|
||||
log_full_source = true
|
||||
log_dir = "./logs/" # Log file path (Can be both relative and absolute).
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include "logger.h"
|
||||
|
||||
static Logger *loggerInstance = nullptr;
|
||||
void *consoleHandle = nullptr;
|
||||
std::mutex logMutex; // Mutex for thread-safe logging
|
||||
|
||||
char timeStr[64];
|
||||
time_t rawTime;
|
||||
tm *timeInfo;
|
||||
SYSTEMTIME systemTime;
|
||||
|
||||
void
|
||||
InitializeLogger (const LogLevel level, const bool logToFile, const std::string& logPath) {
|
||||
if (loggerInstance == nullptr) {
|
||||
loggerInstance = static_cast<Logger *> (malloc (sizeof (Logger)));
|
||||
if (consoleHandle == nullptr) consoleHandle = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
}
|
||||
|
||||
loggerInstance->logLevel = level;
|
||||
|
||||
if (logToFile) {
|
||||
loggerInstance->logFile = fopen (logPath.c_str (), "w"); // Open in write mode
|
||||
if (!loggerInstance->logFile) LogMessage (LogLevel::WARN, std::string ("Failed to open TaikoArcadeLoader.log for writing."));
|
||||
} else loggerInstance->logFile = nullptr; // No file logging
|
||||
}
|
||||
|
||||
void
|
||||
LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const char *format, ...) {
|
||||
// Return if no logger or log level is too high
|
||||
if (loggerInstance == nullptr || messageLevel > loggerInstance->logLevel) return;
|
||||
|
||||
// Lock for thread safety
|
||||
std::lock_guard lock (logMutex);
|
||||
|
||||
// Format the user-provided message
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
int requiredSize = vsnprintf (nullptr, 0, format, args) + 1; // +1 for null terminator
|
||||
std::unique_ptr<char[]> buffer (new char[requiredSize]); // Allocate buffer dynamically
|
||||
vsnprintf (buffer.get (), requiredSize, format, args); // Format the string
|
||||
std::string formattedMessage (buffer.get ()); // Convert to std::string
|
||||
va_end (args);
|
||||
|
||||
// Determine log type string
|
||||
std::string logType = GetLogLevelString (messageLevel);
|
||||
|
||||
// Shrink function name by regex
|
||||
std::string short_function (function);
|
||||
std::regex re(R"(.*? (([\w<>]+::)*[\w]+( [()<>+-]+)?)\(\w+.*?\))");
|
||||
short_function = std::regex_replace (short_function, re, "$1");
|
||||
|
||||
// Remove the absolute path of the build dir
|
||||
constexpr std::string_view build_dir = XSTRING (SOURCE_ROOT);
|
||||
std::string_view filename = codeFile;
|
||||
filename.remove_prefix (build_dir.size ());
|
||||
|
||||
// Get current time and milliseconds
|
||||
SYSTEMTIME systemTime;
|
||||
GetSystemTime (&systemTime);
|
||||
time_t rawTime = time (nullptr);
|
||||
tm *timeInfo = localtime (&rawTime);
|
||||
std::ostringstream timeStamp;
|
||||
timeStamp << std::put_time (timeInfo, "%Y/%m/%d %H:%M:%S") << "." << std::setw (3) << std::setfill ('0') << systemTime.wMilliseconds;
|
||||
|
||||
// Construct the log message
|
||||
std::ostringstream logStream;
|
||||
logStream << short_function << " (" << filename << ":" << codeLine << "): " << formattedMessage;
|
||||
std::string logMessage = logStream.str ();
|
||||
|
||||
// Print the log message
|
||||
std::cout << "[" << timeStamp.str () << "] "; // Timestamp
|
||||
SetConsoleTextAttribute (consoleHandle, GetLogLevelColor (messageLevel)); // Set Level color
|
||||
std::cout << logType; // Level
|
||||
if (messageLevel != LogLevel::ERROR) {
|
||||
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); // Reset console color
|
||||
}
|
||||
std::cout << logMessage << std::endl; // Log message
|
||||
if (messageLevel == LogLevel::ERROR) {
|
||||
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); // Reset console color
|
||||
}
|
||||
std::cout.flush (); // Flush to ensure immediate writing
|
||||
|
||||
if (loggerInstance->logFile != nullptr) {
|
||||
fprintf (loggerInstance->logFile, "[%s] %s%s\n", timeStamp.str ().c_str (), logType.c_str (), logMessage.c_str ());
|
||||
fflush (loggerInstance->logFile); // Flush to ensure immediate writing
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogMessageHandler (const char *function, const char *codeFile, const int codeLine, const LogLevel messageLevel, const wchar_t *format, ...) {
|
||||
const std::string utf8Message = ConvertWideToUtf8 (format); // Convert wide string to UTF-8
|
||||
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
LogMessageHandler (function, codeFile, codeLine, messageLevel, utf8Message.c_str (), args); // Delegate to the original handler
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
bool
|
||||
EnableLogging (LogLevel messageLevel) {
|
||||
return loggerInstance != nullptr && messageLevel <= loggerInstance->logLevel;
|
||||
}
|
||||
|
||||
void
|
||||
CleanupLogger () {
|
||||
if (loggerInstance != nullptr) {
|
||||
if (loggerInstance->logFile) fclose (loggerInstance->logFile);
|
||||
free (loggerInstance);
|
||||
loggerInstance = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers.h"
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
#include <format>
|
||||
#include <wincon.h>
|
||||
|
||||
#define STRING(x) #x
|
||||
#define XSTRING(x) STRING (x)
|
||||
|
||||
enum class LogLevel {
|
||||
NONE = 0,
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
ERROR,
|
||||
#endif
|
||||
WARN,
|
||||
INFO,
|
||||
DEBUG,
|
||||
HOOKS
|
||||
};
|
||||
|
||||
/**
|
||||
* Logger Struct Used to Store Logging Preferences and State
|
||||
*/
|
||||
typedef struct {
|
||||
LogLevel logLevel;
|
||||
FILE *logFile;
|
||||
} Logger;
|
||||
|
||||
/* Initializes a global Logger instance. */
|
||||
void InitializeLogger (LogLevel level, bool logToFile, const std::string& logPath);
|
||||
|
||||
void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const char *format, ...);
|
||||
void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const wchar_t *format, ...);
|
||||
|
||||
bool EnableLogging (LogLevel level);
|
||||
|
||||
/* *
|
||||
* Logs a message with file and line information, if the log level permits.
|
||||
*
|
||||
* Use template magic to replace macros and get proper typing support...
|
||||
*/
|
||||
template <typename... Args>
|
||||
struct LogMessage {
|
||||
LogMessage (const LogLevel level, const std::string_view format, Args &&...args,
|
||||
const std::source_location &loc = std::source_location::current ()) {
|
||||
if (!EnableLogging (level)) return;
|
||||
std::string formatted_message = std::vformat(std::string(format), std::make_format_args(args...));
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ());
|
||||
}
|
||||
|
||||
LogMessage (const LogLevel level, const std::wstring_view format, Args &&...args,
|
||||
const std::source_location &loc = std::source_location::current ()) {
|
||||
if (!EnableLogging (level)) return;
|
||||
std::wstring formatted_message = std::vformat(std::wstring(format), std::make_wformat_args(args...));
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ());
|
||||
}
|
||||
};
|
||||
|
||||
/* *
|
||||
* Logs a message with file and line information, if the log level permits.
|
||||
*/
|
||||
template <>
|
||||
struct LogMessage<void> {
|
||||
LogMessage (const LogLevel level, const std::string_view format, const std::source_location &loc = std::source_location::current ()) {
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, format.data ());
|
||||
}
|
||||
|
||||
LogMessage (const LogLevel level, const std::wstring_view format, const std::source_location &loc = std::source_location::current ()) {
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, format.data ());
|
||||
}
|
||||
};
|
||||
|
||||
LogMessage (LogLevel level, std::string_view format) -> LogMessage<void>;
|
||||
LogMessage (LogLevel level, std::wstring_view format) -> LogMessage<void>;
|
||||
|
||||
template <typename... Args>
|
||||
LogMessage (LogLevel level, std::string_view format, Args &&...ts) -> LogMessage<Args...>;
|
||||
template <typename... Args>
|
||||
LogMessage (LogLevel level, std::wstring_view format, Args &&...ts) -> LogMessage<Args...>;
|
||||
|
||||
/* Converts a string to a LogLevel type. */
|
||||
inline LogLevel
|
||||
GetLogLevel (const std::string &logLevelStr) {
|
||||
if (logLevelStr == "DEBUG") return LogLevel::DEBUG;
|
||||
else if (logLevelStr == "INFO") return LogLevel::INFO;
|
||||
else if (logLevelStr == "WARN") return LogLevel::WARN;
|
||||
else if (logLevelStr == "ERROR") return LogLevel::ERROR;
|
||||
else if (logLevelStr == "HOOKS") return LogLevel::HOOKS;
|
||||
return LogLevel::NONE;
|
||||
}
|
||||
|
||||
/* Converts a LogLevel type to a string for logging. */
|
||||
inline std::string
|
||||
GetLogLevelString (LogLevel messageLevel) {
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG: return "DEBUG: ";
|
||||
case LogLevel::INFO: return "INFO: ";
|
||||
case LogLevel::WARN: return "WARN: ";
|
||||
case LogLevel::ERROR: return "ERROR: ";
|
||||
case LogLevel::HOOKS: return "HOOKS: ";
|
||||
default: return "NONE: ";
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts a LogLevel type to an int for colors display in the console. */
|
||||
inline int
|
||||
GetLogLevelColor (const LogLevel messageLevel) {
|
||||
// Colors: https://i.sstatic.net/ZG625.png
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG: return FOREGROUND_BLUE | FOREGROUND_INTENSITY; // Pale Blue
|
||||
case LogLevel::INFO: return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // Pale Green
|
||||
case LogLevel::WARN: return FOREGROUND_RED | FOREGROUND_GREEN; // Bright Yellow
|
||||
case LogLevel::ERROR: return FOREGROUND_RED; // Bright RED
|
||||
case LogLevel::HOOKS: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; // Pale Purple
|
||||
default: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleans up the logger, closing files if necessary. */
|
||||
void CleanupLogger ();
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "banner.h"
|
||||
|
||||
namespace Banner {
|
||||
|
||||
std::string
|
||||
Version::getVer () {
|
||||
std::string fullVersion = std::string (TAL_VERSION);
|
||||
return fullVersion.substr (0, fullVersion.find("-"));
|
||||
}
|
||||
|
||||
Version::Version () {
|
||||
// Print a cool logo with version info
|
||||
std::cout << R"( )" << std::endl;
|
||||
std::cout << R"( ______ _ __ ___ __ __ __ )" << std::endl;
|
||||
std::cout << R"(/_ __/__ (_) /_____ / _ | ___________ ___/ /__ / / ___ ___ ___/ /__ ____)" << std::endl;
|
||||
std::cout << R"( / / / _ `/ / '_/ _ \/ __ |/ __/ __/ _ `/ _ / -_) /__/ _ \/ _ `/ _ / -_) __/)" << std::endl;
|
||||
std::cout << R"(/_/ \_,_\_/_/\_\\___/_/ |_/_/ \__/\_,_\\_,_/\__/____/\___/\_,_\\_,_/\__/_/ )" << std::endl;
|
||||
std::cout << std::format("{: >79}", std::format("::v{}::", TAL_VERSION)) << std::endl;
|
||||
std::cout << R"( )" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
namespace Banner {
|
||||
class Version {
|
||||
public:
|
||||
|
||||
std::string getVer();
|
||||
|
||||
// Singleton pattern for global access
|
||||
static Version& instance() {
|
||||
static Version instance; // Guaranteed to be destroyed, instantiated on first use
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Version();
|
||||
~Version() = default;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
+51
-92
@@ -1,9 +1,11 @@
|
||||
// ReSharper disable CppDFAUnreachableCode
|
||||
#include <queue>
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches/patches.h"
|
||||
#include "bnusio.h"
|
||||
#include "poll.h"
|
||||
#include "config.h"
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
extern std::vector<HMODULE> plugins;
|
||||
@@ -14,29 +16,29 @@ extern char accessCode2[21];
|
||||
extern char chipId1[33];
|
||||
extern char chipId2[33];
|
||||
|
||||
extern bool emulateUsio;
|
||||
extern bool acceptInvalidCards;
|
||||
static bool emulateUsio = Config::ConfigManager::instance ().getEmulationConfig ().usio;
|
||||
static bool acceptInvalidCards = Config::ConfigManager::instance ().getEmulationConfig ().accept_invalid;
|
||||
extern HWND hGameWnd;
|
||||
|
||||
Keybindings EXIT = {.keycodes = {VK_ESCAPE}};
|
||||
Keybindings TEST = {.keycodes = {VK_F1}};
|
||||
Keybindings SERVICE = {.keycodes = {VK_F2}};
|
||||
Keybindings DEBUG_UP = {.keycodes = {VK_UP}};
|
||||
Keybindings DEBUG_DOWN = {.keycodes = {VK_DOWN}};
|
||||
Keybindings DEBUG_ENTER = {.keycodes = {VK_RETURN}};
|
||||
Keybindings COIN_ADD = {.keycodes = {VK_RETURN}, .buttons = {SDL_GAMEPAD_BUTTON_START}};
|
||||
Keybindings CARD_INSERT_1 = {.keycodes = {'P'}};
|
||||
Keybindings CARD_INSERT_2 = {};
|
||||
Keybindings QR_DATA_READ = {.keycodes = {'Q'}};
|
||||
Keybindings QR_IMAGE_READ = {.keycodes = {'W'}};
|
||||
Keybindings P1_LEFT_BLUE = {.keycodes = {'D'}, .axis = {SDL_AXIS_LEFT_DOWN}};
|
||||
Keybindings P1_LEFT_RED = {.keycodes = {'F'}, .axis = {SDL_AXIS_LEFT_RIGHT}};
|
||||
Keybindings P1_RIGHT_RED = {.keycodes = {'J'}, .axis = {SDL_AXIS_RIGHT_RIGHT}};
|
||||
Keybindings P1_RIGHT_BLUE = {.keycodes = {'K'}, .axis = {SDL_AXIS_RIGHT_DOWN}};
|
||||
Keybindings P2_LEFT_BLUE = {.keycodes = {'Z'}};
|
||||
Keybindings P2_LEFT_RED = {.keycodes = {'X'}};
|
||||
Keybindings P2_RIGHT_RED = {.keycodes = {'C'}};
|
||||
Keybindings P2_RIGHT_BLUE = {.keycodes = {'V'}};
|
||||
static const Keybindings & EXIT = Config::ConfigManager::instance ().getKeyBindings ().exit();
|
||||
static const Keybindings & TEST = Config::ConfigManager::instance ().getKeyBindings ().test();
|
||||
static const Keybindings & SERVICE = Config::ConfigManager::instance ().getKeyBindings ().service();
|
||||
static const Keybindings & DEBUG_UP = Config::ConfigManager::instance ().getKeyBindings ().debug_up();
|
||||
static const Keybindings & DEBUG_DOWN = Config::ConfigManager::instance ().getKeyBindings ().debug_down();
|
||||
static const Keybindings & DEBUG_ENTER = Config::ConfigManager::instance ().getKeyBindings ().debug_enter();
|
||||
static const Keybindings & COIN_ADD = Config::ConfigManager::instance ().getKeyBindings ().coin_add();
|
||||
static const Keybindings & CARD_INSERT_1 = Config::ConfigManager::instance ().getKeyBindings ().card_insert_1();
|
||||
static const Keybindings & CARD_INSERT_2 = Config::ConfigManager::instance ().getKeyBindings ().card_insert_2();
|
||||
static const Keybindings & QR_DATA_READ = Config::ConfigManager::instance ().getKeyBindings ().qr_data_read();
|
||||
static const Keybindings & QR_IMAGE_READ = Config::ConfigManager::instance ().getKeyBindings ().qr_image_read();
|
||||
static const Keybindings & P1_LEFT_BLUE = Config::ConfigManager::instance ().getKeyBindings ().p1_left_blue();
|
||||
static const Keybindings & P1_LEFT_RED = Config::ConfigManager::instance ().getKeyBindings ().p1_left_red();
|
||||
static const Keybindings & P1_RIGHT_RED = Config::ConfigManager::instance ().getKeyBindings ().p1_right_red();
|
||||
static const Keybindings & P1_RIGHT_BLUE = Config::ConfigManager::instance ().getKeyBindings ().p1_right_blue();
|
||||
static const Keybindings & P2_LEFT_BLUE = Config::ConfigManager::instance ().getKeyBindings ().p2_left_blue();
|
||||
static const Keybindings & P2_LEFT_RED = Config::ConfigManager::instance ().getKeyBindings ().p2_left_red();
|
||||
static const Keybindings & P2_RIGHT_RED = Config::ConfigManager::instance ().getKeyBindings ().p2_right_red();
|
||||
static const Keybindings & P2_RIGHT_BLUE = Config::ConfigManager::instance ().getKeyBindings ().p2_right_blue();
|
||||
|
||||
const int exitWait = 100;
|
||||
int exited = 0;
|
||||
@@ -50,7 +52,16 @@ bool updateByCoin = false;
|
||||
HWND windowHandle = nullptr;
|
||||
float axisThreshold = 0.6f;
|
||||
u8 inputState = 1 | (1 << 2);
|
||||
bool globalKeyboard = false;
|
||||
bool globalKeyboard = Config::ConfigManager::instance ().getControllerConfig ().global_keyboard;
|
||||
bool waitAll = false;
|
||||
short drumWaitPeriod = Config::ConfigManager::instance ().getControllerConfig ().wait_period;
|
||||
bool analogInput = Config::ConfigManager::instance ().getControllerConfig ().analog_input;
|
||||
u16 buttonWaitPeriod[] = { 0, 0 };
|
||||
std::queue<u8> buttonQueue[] = { {}, {} };
|
||||
bool valueStates[] = {false, false, false, false, false, false, false, false};
|
||||
const Keybindings *analogButtons[] = {
|
||||
&P1_LEFT_BLUE, &P1_LEFT_RED, &P1_RIGHT_RED, &P1_RIGHT_BLUE, &P2_LEFT_BLUE, &P2_LEFT_RED, &P2_RIGHT_RED, &P2_RIGHT_BLUE
|
||||
};
|
||||
|
||||
namespace bnusio {
|
||||
HMODULE bnusioOriginal = LoadLibrary ("bnusio_original.dll");
|
||||
@@ -136,10 +147,9 @@ BNUSIO_EXPORT (u16, bnusio_GetService, i32 a1) {
|
||||
}
|
||||
}
|
||||
|
||||
bool analogInput = false;
|
||||
SDLAxis analogBindings[] = {
|
||||
SDL_AXIS_LEFT_LEFT, SDL_AXIS_LEFT_RIGHT, SDL_AXIS_LEFT_DOWN, SDL_AXIS_LEFT_UP, // P1: LB, LR, RR, RB
|
||||
SDL_AXIS_RIGHT_LEFT, SDL_AXIS_RIGHT_RIGHT, SDL_AXIS_RIGHT_DOWN, SDL_AXIS_RIGHT_UP, // P2: LB, LR, RR, RB
|
||||
SDLAxis::SDL_AXIS_LEFT_LEFT, SDLAxis::SDL_AXIS_LEFT_RIGHT, SDLAxis::SDL_AXIS_LEFT_DOWN, SDLAxis::SDL_AXIS_LEFT_UP, // P1: LB, LR, RR, RB
|
||||
SDLAxis::SDL_AXIS_RIGHT_LEFT, SDLAxis::SDL_AXIS_RIGHT_RIGHT, SDLAxis::SDL_AXIS_RIGHT_DOWN, SDLAxis::SDL_AXIS_RIGHT_UP, // P2: LB, LR, RR, RB
|
||||
};
|
||||
u16 __fastcall
|
||||
AnalogInputAxis (const u8 which) {
|
||||
@@ -147,14 +157,6 @@ AnalogInputAxis (const u8 which) {
|
||||
return analogIn > 100 ? analogIn : 0;
|
||||
}
|
||||
|
||||
bool waitAll = false;
|
||||
short drumWaitPeriod = 0;
|
||||
u16 buttonWaitPeriod[] = { 0, 0 };
|
||||
std::queue<u8> buttonQueue[] = { {}, {} };
|
||||
bool valueStates[] = {false, false, false, false, false, false, false, false};
|
||||
Keybindings *analogButtons[] = {
|
||||
&P1_LEFT_BLUE, &P1_LEFT_RED, &P1_RIGHT_RED, &P1_RIGHT_BLUE, &P2_LEFT_BLUE, &P2_LEFT_RED, &P2_RIGHT_RED, &P2_RIGHT_BLUE
|
||||
};
|
||||
u16 __fastcall
|
||||
AnalogInputWaitPeriod (const u8 which) {
|
||||
const auto button = analogButtons[which];
|
||||
@@ -215,83 +217,36 @@ AnalogInputSimple (const u8 which) {
|
||||
|
||||
void
|
||||
Init () {
|
||||
SetKeyboardButtons ();
|
||||
|
||||
int fpsLimit = 0;
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
const toml_table_t *config = config_ptr.get ();
|
||||
if (const auto controller = openConfigSection (config, "controller")) {
|
||||
drumWaitPeriod = static_cast<short> (readConfigInt (controller, "wait_period", drumWaitPeriod));
|
||||
analogInput = readConfigBool (controller, "analog_input", analogInput);
|
||||
globalKeyboard = readConfigBool (controller, "global_keyboard", globalKeyboard);
|
||||
}
|
||||
// auto graphics = openConfigSection (config, "graphics");
|
||||
// if (graphics) {
|
||||
// fpsLimit = (int)readConfigInt (graphics, "fpslimit", fpsLimit);
|
||||
// }
|
||||
}
|
||||
updateByCoin = fpsLimit == 0;
|
||||
// if (updateByCoin) {
|
||||
// LogMessage (LogLevel::INFO, "fpsLimit is set to 0, bnusio::Update() will invoke in getCoin callback");
|
||||
// }
|
||||
|
||||
if (analogInput) {
|
||||
LogMessage (LogLevel::WARN, "[Analog Type] Axis: All the keyboard drum inputs have been disabled");
|
||||
LogMessage (LogLevel::WARN, "Using Axis AnalogIn: All the keyboard drum inputs have been disabled");
|
||||
analogMethod = AnalogInputAxis;
|
||||
} else if (drumWaitPeriod > 0) {
|
||||
LogMessage (LogLevel::WARN, "[Analog Type] WaitPeriod: Fast input might be queued");
|
||||
LogMessage (LogLevel::WARN, "Using WaitPeriod AnalogIn: Fast input might be queued");
|
||||
analogMethod = AnalogInputWaitPeriod;
|
||||
} else if (drumWaitPeriod == 0) {
|
||||
LogMessage (LogLevel::INFO, "[Analog Type] Cooldown: Fastest and original input");
|
||||
analogMethod = AnalogInputCooldown;
|
||||
// } else if (drumWaitPeriod == 0) {
|
||||
// LogMessage (LogLevel::INFO, "Using Cooldown AnalogIn: Fastest and original input");
|
||||
// analogMethod = AnalogInputCooldown;
|
||||
} else {
|
||||
LogMessage (LogLevel::INFO, "[Analog Type] Simple: Fastest and original input");
|
||||
LogMessage (LogLevel::INFO, "Using Simple AnalogIn: Fastest and original input");
|
||||
analogMethod = AnalogInputSimple;
|
||||
}
|
||||
|
||||
const auto keyConfigPath = std::filesystem::current_path () / "keyconfig.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> keyConfig_ptr (openConfig (keyConfigPath), toml_free);
|
||||
if (keyConfig_ptr) {
|
||||
inputState = 0;
|
||||
if (analogInput) inputState |= (1 << 2);
|
||||
const toml_table_t *keyConfig = keyConfig_ptr.get ();
|
||||
SetConfigValue (keyConfig, "EXIT", &EXIT, &inputState);
|
||||
|
||||
SetConfigValue (keyConfig, "TEST", &TEST, &inputState);
|
||||
SetConfigValue (keyConfig, "SERVICE", &SERVICE, &inputState);
|
||||
SetConfigValue (keyConfig, "DEBUG_UP", &DEBUG_UP, &inputState);
|
||||
SetConfigValue (keyConfig, "DEBUG_DOWN", &DEBUG_DOWN, &inputState);
|
||||
SetConfigValue (keyConfig, "DEBUG_ENTER", &DEBUG_ENTER, &inputState);
|
||||
|
||||
SetConfigValue (keyConfig, "COIN_ADD", &COIN_ADD, &inputState);
|
||||
SetConfigValue (keyConfig, "CARD_INSERT_1", &CARD_INSERT_1, &inputState);
|
||||
SetConfigValue (keyConfig, "CARD_INSERT_2", &CARD_INSERT_2, &inputState);
|
||||
SetConfigValue (keyConfig, "QR_DATA_READ", &QR_DATA_READ, &inputState);
|
||||
SetConfigValue (keyConfig, "QR_IMAGE_READ", &QR_IMAGE_READ, &inputState);
|
||||
|
||||
SetConfigValue (keyConfig, "P1_LEFT_BLUE", &P1_LEFT_BLUE, &inputState);
|
||||
SetConfigValue (keyConfig, "P1_LEFT_RED", &P1_LEFT_RED, &inputState);
|
||||
SetConfigValue (keyConfig, "P1_RIGHT_RED", &P1_RIGHT_RED, &inputState);
|
||||
SetConfigValue (keyConfig, "P1_RIGHT_BLUE", &P1_RIGHT_BLUE, &inputState);
|
||||
SetConfigValue (keyConfig, "P2_LEFT_BLUE", &P2_LEFT_BLUE, &inputState);
|
||||
SetConfigValue (keyConfig, "P2_LEFT_RED", &P2_LEFT_RED, &inputState);
|
||||
SetConfigValue (keyConfig, "P2_RIGHT_RED", &P2_RIGHT_RED, &inputState);
|
||||
SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &inputState);
|
||||
}
|
||||
|
||||
LogMessage (LogLevel::INFO, "Finish Loading keyconfig.toml useKeyboard={} useMouse={} useController={}",
|
||||
(inputState & 1) ? "true" : "false", (inputState & (1 << 1)) ? "true" : "false", (inputState & (1 << 2)) ? "true" : "false");
|
||||
|
||||
if (!emulateUsio && !exists (std::filesystem::current_path () / "bnusio_original.dll")) {
|
||||
emulateUsio = true;
|
||||
LogMessage (LogLevel::ERROR, "bnusio_original.dll not found! usio emulation enabled");
|
||||
}
|
||||
|
||||
if (!emulateUsio && bnusioOriginal) {
|
||||
LogMessage (LogLevel::WARN, "USIO emulation disabled");
|
||||
LogMessage (LogLevel::WARN, "Disable USIO Emulation");
|
||||
} else {
|
||||
LogMessage (LogLevel::INFO, "Using USIO Emulation");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,8 +262,12 @@ Update () {
|
||||
UpdatePoll (windowHandle);
|
||||
|
||||
std::vector<uint8_t> buffer = {};
|
||||
if (IsButtonTapped (COIN_ADD)) coin_count++;
|
||||
if (IsButtonTapped (SERVICE)) service_count++;
|
||||
if (IsButtonTapped (COIN_ADD)) {
|
||||
coin_count++;
|
||||
}
|
||||
if (IsButtonTapped (SERVICE)) {
|
||||
service_count++;
|
||||
}
|
||||
if (IsButtonTapped (TEST)) testEnabled = !testEnabled;
|
||||
if (exited == 0 && IsButtonTapped (EXIT)) {
|
||||
LogMessage (LogLevel::INFO, "Exit by Press Exit Button!");
|
||||
@@ -331,6 +290,6 @@ Update () {
|
||||
void
|
||||
Close () {
|
||||
// patches::Plugins::Exit ();
|
||||
CleanupLogger ();
|
||||
Logger::CleanupLogger ();
|
||||
}
|
||||
} // namespace bnusio
|
||||
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <rfl/toml.hpp>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "banner.h"
|
||||
#include "config.h"
|
||||
#include "logger.h"
|
||||
|
||||
static bool usingKeyboard = false;
|
||||
static bool usingMouse = false;
|
||||
static bool usingController = false;
|
||||
|
||||
|
||||
namespace Config {
|
||||
bool
|
||||
ConfigManager::validateConfigfile (std::string path) {
|
||||
std::filesystem::path configPath = path;
|
||||
if (!exists (configPath) || !configPath.has_filename ()) {
|
||||
std::cerr << configPath.string () << ": file does not exist" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream stream (configPath);
|
||||
if (!stream.is_open ()) {
|
||||
std::cerr << "Could not open " << configPath.string () << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = rfl::toml::read<struct globalConfig> (stream);
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
auto error = result.error ().value ();
|
||||
std::cerr << "Validate config failed with error: " << error.what () << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ConfigManager::loadConfig () {
|
||||
std::lock_guard lock (mutex);
|
||||
|
||||
if (isLoaded) { return true; }
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
|
||||
if (!exists (configPath) || !configPath.has_filename ()) {
|
||||
LogMessage (LogLevel::WARN, std::string (configPath.string ()) + ": file does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream stream (configPath);
|
||||
if (!stream.is_open ()) {
|
||||
LogMessage (LogLevel::WARN, "Could not open " + std::string (configPath.string ()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = rfl::toml::read<struct globalConfig, rfl::DefaultIfMissing> (stream);
|
||||
if (result) {
|
||||
config = result.value ();
|
||||
bool success = loadKeyBindings ();
|
||||
if (!success) {
|
||||
LogMessage (LogLevel::ERROR, "Failed to load keybindings");
|
||||
MessageBoxA (nullptr, "Failed to load keybindings, check logs for error", nullptr, MB_OK);
|
||||
ExitProcess (0);
|
||||
}
|
||||
isLoaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto error = result.error ().value ();
|
||||
LogMessage (LogLevel::WARN, "Read config failed with error: " + error.what ());
|
||||
return false;
|
||||
}
|
||||
|
||||
const qrConfig &
|
||||
ConfigManager::getQrConfig () {
|
||||
auto result = updateQrConfig ();
|
||||
if (!result) {
|
||||
LogMessage (LogLevel::ERROR, "Failed to update QR config");
|
||||
MessageBoxA (nullptr, "Failed to update QR config", nullptr, MB_OK);
|
||||
ExitProcess (0);
|
||||
}
|
||||
return config.qr;
|
||||
|
||||
}
|
||||
|
||||
ConfigManager::ConfigManager () {
|
||||
Banner::Version::instance ();
|
||||
Logger::InitializeLogger (LogLevel::INFO, false, "");
|
||||
auto result = loadConfig ();
|
||||
if (!result) {
|
||||
LogMessage (LogLevel::ERROR, "Failed to load config file");
|
||||
MessageBoxA (nullptr, "Failed to load config", nullptr, MB_OK);
|
||||
ExitProcess (0);
|
||||
}
|
||||
Logger::CleanupLogger ();
|
||||
}
|
||||
|
||||
bool
|
||||
ConfigManager::loadKeyBindings () {
|
||||
LogMessage (LogLevel::INFO, "Using Keyboard Layout: {}", config.keyboard.jp_layout ? "JP" : "US");
|
||||
ConfigKeyboardButtons = config.keyboard.jp_layout ? std::map(ConfigKeyboardButtons_JP) : std::map(ConfigKeyboardButtons_US);
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "keyconfig.toml";
|
||||
if (!exists (configPath) || !configPath.has_filename ()) {
|
||||
LogMessage (LogLevel::WARN, std::string (configPath.string ()) + ": file does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream stream (configPath);
|
||||
if (!stream.is_open ()) {
|
||||
LogMessage (LogLevel::WARN, "Could not open " + std::string (configPath.string ()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = rfl::toml::read<struct keybindingConfig> (stream);
|
||||
if (result) {
|
||||
keyBindings = result.value ();
|
||||
keyBindings.usingKeyboard = usingKeyboard;
|
||||
keyBindings.usingMouse = usingMouse;
|
||||
keyBindings.usingController = usingController;
|
||||
LogMessage (LogLevel::DEBUG, "Finish Loading keyconfig.toml");
|
||||
if (usingKeyboard) LogMessage (LogLevel::INFO, "Using Input Channel: Keyboard");
|
||||
if (usingMouse) LogMessage (LogLevel::INFO, "Using Input Channel: Mouse Wheel");
|
||||
if (usingController) LogMessage (LogLevel::INFO, "Using Input Channel: Controller");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto error = result.error ().value ();
|
||||
LogMessage (LogLevel::WARN, "Read keybindings failed with error: " + error.what ());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ConfigManager::updateQrConfig () {
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
if (!exists (configPath) || !configPath.has_filename ()) {
|
||||
LogMessage (LogLevel::WARN, std::string (configPath.string ()) + ": file does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream stream (configPath);
|
||||
if (!stream.is_open ()) {
|
||||
LogMessage (LogLevel::WARN, "Could not open " + std::string (configPath.string ()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = rfl::toml::read<struct qrConfig, rfl::DefaultIfMissing> (stream);
|
||||
if (result) {
|
||||
config.qr = result.value ();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto error = result.error ().value ();
|
||||
LogMessage (LogLevel::WARN, "Read config failed with error: " + error.what ());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct rfl::Reflector<Keybindings> {
|
||||
using ReflType = std::vector<std::string>;
|
||||
|
||||
static ConfigValue StringToConfigEnum(const std::string& value) {
|
||||
ConfigValue ret = {};
|
||||
if (Config::ConfigManager::ConfigKeyboardButtons.contains (value)) {
|
||||
usingKeyboard = true;
|
||||
ret.type = EnumType::keycode;
|
||||
ret.keycode = Config::ConfigManager::ConfigKeyboardButtons.at (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Config::ConfigManager::ConfigControllerButtons.contains (value)) {
|
||||
usingController = true;
|
||||
ret.type = EnumType::button;
|
||||
ret.button = Config::ConfigManager::ConfigControllerButtons.at (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Config::ConfigManager::ConfigControllerAXIS.contains (value)) {
|
||||
usingController = true;
|
||||
ret.type = EnumType::axis;
|
||||
ret.axis = Config::ConfigManager::ConfigControllerAXIS.at (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (Config::ConfigManager::ConfigMouseScroll.contains (value)) {
|
||||
usingMouse = true;
|
||||
ret.type = EnumType::scroll;
|
||||
ret.scroll = Config::ConfigManager::ConfigMouseScroll.at (value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LogMessage(LogLevel::ERROR, "Unknown key config value: {}", value);
|
||||
throw std::exception(std::format ("Unknown key config value: {}", value).c_str());
|
||||
}
|
||||
|
||||
static Keybindings to(const ReflType& value) {
|
||||
Keybindings result {};
|
||||
result.buttons.fill (SDL_GAMEPAD_BUTTON_INVALID);
|
||||
for (const auto& key : value) {
|
||||
const auto config = StringToConfigEnum(key);
|
||||
switch (config.type) {
|
||||
case EnumType::keycode:
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=keycode value={}", key, static_cast<int>(config.keycode));
|
||||
for (auto &keycode : result.keycodes) {
|
||||
if (keycode == 0) {
|
||||
keycode = config.keycode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EnumType::button:
|
||||
LogMessage(LogLevel::DEBUG, "config {} type=button value={}", key, static_cast<int>(config.button));
|
||||
for (auto &button : result.buttons) {
|
||||
if (button == SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
button = config.button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EnumType::axis:
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=axis value={}", key, static_cast<int>(config.axis));
|
||||
for (auto &axis : result.axis) {
|
||||
if (axis == SDLAxis::SDL_AXIS_NULL) {
|
||||
axis = config.axis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EnumType::scroll:
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=scroll value={}", key, static_cast<int>(config.scroll));
|
||||
for (auto &scroll : result.scroll) {
|
||||
if (scroll == Scroll::MOUSE_SCROLL_INVALID) {
|
||||
scroll = config.scroll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EnumType::none:
|
||||
default:
|
||||
throw std::exception("Invalid keybinding type");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <rfl.hpp>
|
||||
|
||||
#include "poll.h"
|
||||
|
||||
namespace Config {
|
||||
|
||||
using chassisIdLimit = rfl::Validator<std::string, rfl::Size<rfl::Maximum<15>>>;
|
||||
struct amauthConfig {
|
||||
std::string server = "127.0.0.1";
|
||||
std::string port = "54430";
|
||||
chassisIdLimit chassis_id = "284111080000";
|
||||
std::string shop_id = "TAIKO ARCADE LOADER";
|
||||
std::string game_ver = "00.00";
|
||||
std::string country_code = "JPN";
|
||||
|
||||
std::string full_address() const {
|
||||
auto result = server + (port.empty() ? "" : ":" + port);
|
||||
if (result.size() > 255) {
|
||||
result.resize(255);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string place_id() const {
|
||||
// Truncate to max 15 characters
|
||||
auto result = country_code + "0FF0";
|
||||
if (result.size() > 15) {
|
||||
result.resize(15);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
using patchVersions = rfl::Literal<"auto", "JPN00", "JPN08", "JPN39", "CHN00">;
|
||||
|
||||
struct patchesConfig {
|
||||
patchVersions version{"auto"};
|
||||
bool unlock_songs = true;
|
||||
bool local_files = true;
|
||||
// int maximum_song = 1600;
|
||||
struct chn00Config {
|
||||
bool fix_language = false;
|
||||
bool demo_movie = true;
|
||||
bool mode_collabo025 = false;
|
||||
bool mode_collabo026 = false;
|
||||
};
|
||||
chn00Config chn00;
|
||||
};
|
||||
|
||||
struct emulationConfig {
|
||||
bool usio = true;
|
||||
bool card_reader = true;
|
||||
bool accept_invalid = false;
|
||||
bool qr = true;
|
||||
};
|
||||
|
||||
struct graphicsConfig {
|
||||
bool windowed = false;
|
||||
bool cursor = true;
|
||||
struct resConfig {
|
||||
int x = 1920;
|
||||
int y = 1080;
|
||||
};
|
||||
resConfig res;
|
||||
bool vsync = false;
|
||||
float model_res_rate = 1.0f;
|
||||
};
|
||||
|
||||
struct audioConfig {
|
||||
bool real = true;
|
||||
bool wasapi_shared = true;
|
||||
bool asio = false;
|
||||
std::string asio_driver = "ASIO4ALL v2";
|
||||
};
|
||||
|
||||
struct qrConfig {
|
||||
std::string image_path = "";
|
||||
struct qrDataConfig {
|
||||
std::string serial = "";
|
||||
int type = 0;
|
||||
std::vector<int> song_no;
|
||||
};
|
||||
qrDataConfig data;
|
||||
};
|
||||
|
||||
struct controllerConfig {
|
||||
int wait_period = 0;
|
||||
bool analog_input = false;
|
||||
bool global_keyboard = false;
|
||||
bool simple_input = false;
|
||||
};
|
||||
|
||||
struct keyboardConfig {
|
||||
bool auto_ime = true;
|
||||
bool jp_layout = false;
|
||||
};
|
||||
|
||||
struct layeredfsConfig {
|
||||
bool enabled = false;
|
||||
std::string mod_dir = "Data_mods";
|
||||
};
|
||||
|
||||
using logLevels = rfl::Literal<"NONE", "ERROR", "WARN", "INFO", "GAME", "DEBUG", "HOOKS">;
|
||||
|
||||
struct loggingConfig {
|
||||
logLevels log_level{ "GAME" };
|
||||
bool log_to_file = false;
|
||||
bool log_method_name = false;
|
||||
bool log_full_source = false;
|
||||
std::string log_dir = "./logs/";
|
||||
};
|
||||
|
||||
struct globalConfig {
|
||||
amauthConfig amauth;
|
||||
patchesConfig patches;
|
||||
emulationConfig emulation;
|
||||
graphicsConfig graphics;
|
||||
audioConfig audio;
|
||||
qrConfig qr;
|
||||
controllerConfig controller;
|
||||
keyboardConfig keyboard;
|
||||
layeredfsConfig layeredfs;
|
||||
loggingConfig logging;
|
||||
};
|
||||
|
||||
struct keybindingConfig {
|
||||
rfl::Rename<"EXIT", Keybindings> exit = Keybindings{.keycodes = {VK_ESCAPE}};
|
||||
rfl::Rename<"TEST", Keybindings> test = Keybindings{.keycodes = {VK_F1}};
|
||||
rfl::Rename<"SERVICE", Keybindings> service = Keybindings{.keycodes = {VK_F2}};
|
||||
rfl::Rename<"DEBUG_UP", Keybindings> debug_up = Keybindings{.keycodes = {VK_UP}};
|
||||
rfl::Rename<"DEBUG_DOWN", Keybindings> debug_down = Keybindings{.keycodes = {VK_DOWN}};
|
||||
rfl::Rename<"DEBUG_ENTER", Keybindings> debug_enter = Keybindings{.keycodes = {VK_RETURN}};
|
||||
rfl::Rename<"COIN_ADD", Keybindings> coin_add = Keybindings{.keycodes = {VK_RETURN}, .buttons = {SDL_GAMEPAD_BUTTON_START}};
|
||||
rfl::Rename<"CARD_INSERT_1", Keybindings> card_insert_1 = Keybindings{.keycodes = {'P'}};
|
||||
rfl::Rename<"CARD_INSERT_2", Keybindings> card_insert_2 = Keybindings{.keycodes = {}};
|
||||
rfl::Rename<"QR_DATA_READ", Keybindings> qr_data_read = Keybindings{.keycodes = {'Q'}};
|
||||
rfl::Rename<"QR_IMAGE_READ", Keybindings> qr_image_read = Keybindings{.keycodes = {'W'}};
|
||||
rfl::Rename<"P1_LEFT_BLUE", Keybindings> p1_left_blue = Keybindings{.keycodes = {'D'}, .axis = {SDLAxis::SDL_AXIS_LEFT_DOWN}};
|
||||
rfl::Rename<"P1_LEFT_RED", Keybindings> p1_left_red = Keybindings{.keycodes = {'F'}, .axis = {SDLAxis::SDL_AXIS_LEFT_RIGHT}};
|
||||
rfl::Rename<"P1_RIGHT_RED", Keybindings> p1_right_red = Keybindings{.keycodes = {'J'}, .axis = {SDLAxis::SDL_AXIS_RIGHT_RIGHT}};
|
||||
rfl::Rename<"P1_RIGHT_BLUE", Keybindings> p1_right_blue = Keybindings{.keycodes = {'K'}, .axis = {SDLAxis::SDL_AXIS_RIGHT_DOWN}};
|
||||
rfl::Rename<"P2_LEFT_BLUE", Keybindings> p2_left_blue = Keybindings{.keycodes = {'Z'}};
|
||||
rfl::Rename<"P2_LEFT_RED", Keybindings> p2_left_red = Keybindings{.keycodes = {'X'}};
|
||||
rfl::Rename<"P2_RIGHT_RED", Keybindings> p2_right_red = Keybindings{.keycodes = {'C'}};
|
||||
rfl::Rename<"P2_RIGHT_BLUE", Keybindings> p2_right_blue = Keybindings{.keycodes = {'V'}};
|
||||
rfl::Skip<bool> usingKeyboard;
|
||||
rfl::Skip<bool> usingMouse;
|
||||
rfl::Skip<bool> usingController;
|
||||
};
|
||||
|
||||
class ConfigManager {
|
||||
public:
|
||||
inline static const std::map<std::string, u8> ConfigKeyboardButtons_US = {
|
||||
// Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Row 1
|
||||
{"ESCAPE", VK_ESCAPE},
|
||||
{"F1", VK_F1},
|
||||
{"F2", VK_F2},
|
||||
{"F3", VK_F3},
|
||||
{"F4", VK_F4},
|
||||
{"F5", VK_F5},
|
||||
{"F6", VK_F6},
|
||||
{"F7", VK_F7},
|
||||
{"F8", VK_F8},
|
||||
{"F9", VK_F9},
|
||||
{"F10", VK_F10},
|
||||
{"F11", VK_F11},
|
||||
{"F12", VK_F12},
|
||||
|
||||
// Row 2
|
||||
{"`", VK_OEM_3},
|
||||
{"1", '1'},
|
||||
{"2", '2'},
|
||||
{"3", '3'},
|
||||
{"4", '4'},
|
||||
{"5", '5'},
|
||||
{"6", '6'},
|
||||
{"7", '7'},
|
||||
{"8", '8'},
|
||||
{"9", '9'},
|
||||
{"0", '0'},
|
||||
{"-", VK_OEM_MINUS},
|
||||
{"=", VK_OEM_PLUS},
|
||||
{"BACKSPACE", VK_BACK},
|
||||
|
||||
// Row 3
|
||||
{"TAB", VK_TAB},
|
||||
{"Q", 'Q'},
|
||||
{"W", 'W'},
|
||||
{"E", 'E'},
|
||||
{"R", 'R'},
|
||||
{"T", 'T'},
|
||||
{"Y", 'Y'},
|
||||
{"U", 'U'},
|
||||
{"I", 'I'},
|
||||
{"O", 'O'},
|
||||
{"P", 'P'},
|
||||
{"[", VK_OEM_4},
|
||||
{"]", VK_OEM_6},
|
||||
{"BACKSLASH", VK_OEM_5},
|
||||
|
||||
// Row 4
|
||||
{"CAPS_LOCK", VK_CAPITAL},
|
||||
{"A", 'A'},
|
||||
{"S", 'S'},
|
||||
{"D", 'D'},
|
||||
{"F", 'F'},
|
||||
{"G", 'G'},
|
||||
{"H", 'H'},
|
||||
{"J", 'J'},
|
||||
{"K", 'K'},
|
||||
{"L", 'L'},
|
||||
{";", VK_OEM_1},
|
||||
{"'", VK_OEM_7},
|
||||
{"ENTER", VK_RETURN},
|
||||
|
||||
// Row 5
|
||||
{"SHIFT", VK_SHIFT},
|
||||
{"Z", 'Z'},
|
||||
{"X", 'X'},
|
||||
{"C", 'C'},
|
||||
{"V", 'V'},
|
||||
{"B", 'B'},
|
||||
{"N", 'N'},
|
||||
{"M", 'M'},
|
||||
{",", VK_OEM_COMMA},
|
||||
{".", VK_OEM_PERIOD},
|
||||
{"SLASH", VK_OEM_2},
|
||||
|
||||
// Row 6
|
||||
{"CONTROL", VK_CONTROL},
|
||||
{"L_WIN", VK_LWIN},
|
||||
{"ALT", VK_MENU},
|
||||
{"SPACE", VK_SPACE},
|
||||
{"R_WIN", VK_RWIN},
|
||||
{"MENU", VK_APPS},
|
||||
|
||||
// Other Keys
|
||||
// PrtSc is more important when making snapshots, therefore comment it as reserved
|
||||
//{"PRINT_SCREEN", VK_SNAPSHOT},
|
||||
{"SCROLL_LOCK", VK_SCROLL},
|
||||
{"PAUSE", VK_PAUSE},
|
||||
{"INSERT", VK_INSERT},
|
||||
{"DELETE", VK_DELETE},
|
||||
{"HOME", VK_HOME},
|
||||
{"END", VK_END},
|
||||
{"PAGE_UP", VK_PRIOR},
|
||||
{"PAGE_DOWN", VK_NEXT},
|
||||
|
||||
// Arrow Keys
|
||||
{"UPARROW", VK_UP},
|
||||
{"LEFTARROW", VK_LEFT},
|
||||
{"DOWNARROW", VK_DOWN},
|
||||
{"RIGHTARROW", VK_RIGHT},
|
||||
|
||||
// NUMPAD Keys
|
||||
{"NUM_LOCK", VK_NUMLOCK},
|
||||
{"DIVIDE", VK_DIVIDE},
|
||||
{"MULTIPLY", VK_MULTIPLY},
|
||||
{"SUBTRACT", VK_SUBTRACT},
|
||||
{"NUM7", VK_NUMPAD7},
|
||||
{"NUM8", VK_NUMPAD8},
|
||||
{"NUM9", VK_NUMPAD9},
|
||||
{"ADD", VK_ADD},
|
||||
{"NUM4", VK_NUMPAD4},
|
||||
{"NUM5", VK_NUMPAD5},
|
||||
{"NUM6", VK_NUMPAD6},
|
||||
{"NUM1", VK_NUMPAD1},
|
||||
{"NUM2", VK_NUMPAD2},
|
||||
{"NUM3", VK_NUMPAD3},
|
||||
{"NUM0", VK_NUMPAD0},
|
||||
{"DECIMAL", VK_DECIMAL},
|
||||
};
|
||||
inline static const std::map<std::string, u8> ConfigKeyboardButtons_JP = {
|
||||
// Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Row 1
|
||||
{"ESCAPE", VK_ESCAPE},
|
||||
{"F1", VK_F1},
|
||||
{"F2", VK_F2},
|
||||
{"F3", VK_F3},
|
||||
{"F4", VK_F4},
|
||||
{"F5", VK_F5},
|
||||
{"F6", VK_F6},
|
||||
{"F7", VK_F7},
|
||||
{"F8", VK_F8},
|
||||
{"F9", VK_F9},
|
||||
{"F10", VK_F10},
|
||||
{"F11", VK_F11},
|
||||
{"F12", VK_F12},
|
||||
|
||||
// Row 2
|
||||
{"1", '1'},
|
||||
{"2", '2'},
|
||||
{"3", '3'},
|
||||
{"4", '4'},
|
||||
{"5", '5'},
|
||||
{"6", '6'},
|
||||
{"7", '7'},
|
||||
{"8", '8'},
|
||||
{"9", '9'},
|
||||
{"0", '0'},
|
||||
{"-", VK_OEM_MINUS},
|
||||
{"^", VK_OEM_7},
|
||||
{"YEN", VK_OEM_5},
|
||||
{"BACKSPACE", VK_BACK},
|
||||
|
||||
// Row 3
|
||||
{"TAB", VK_TAB},
|
||||
{"Q", 'Q'},
|
||||
{"W", 'W'},
|
||||
{"E", 'E'},
|
||||
{"R", 'R'},
|
||||
{"T", 'T'},
|
||||
{"Y", 'Y'},
|
||||
{"U", 'U'},
|
||||
{"I", 'I'},
|
||||
{"O", 'O'},
|
||||
{"P", 'P'},
|
||||
{"@", VK_OEM_3},
|
||||
{"[", VK_OEM_4},
|
||||
|
||||
// Row 4
|
||||
{"CAPS_LOCK", VK_CAPITAL},
|
||||
{"A", 'A'},
|
||||
{"S", 'S'},
|
||||
{"D", 'D'},
|
||||
{"F", 'F'},
|
||||
{"G", 'G'},
|
||||
{"H", 'H'},
|
||||
{"J", 'J'},
|
||||
{"K", 'K'},
|
||||
{"L", 'L'},
|
||||
{";", VK_OEM_PLUS},
|
||||
{":", VK_OEM_1},
|
||||
{"]", VK_OEM_6},
|
||||
{"ENTER", VK_RETURN},
|
||||
|
||||
// Row 5
|
||||
{"SHIFT", VK_SHIFT},
|
||||
{"Z", 'Z'},
|
||||
{"X", 'X'},
|
||||
{"C", 'C'},
|
||||
{"V", 'V'},
|
||||
{"B", 'B'},
|
||||
{"N", 'N'},
|
||||
{"M", 'M'},
|
||||
{",", VK_OEM_COMMA},
|
||||
{".", VK_OEM_PERIOD},
|
||||
{"SLASH", VK_OEM_2},
|
||||
{"BACKSLASH", VK_OEM_102},
|
||||
|
||||
// Row 6
|
||||
{"CONTROL", VK_CONTROL},
|
||||
{"L_WIN", VK_LWIN},
|
||||
{"ALT", VK_MENU},
|
||||
{"SPACE", VK_SPACE},
|
||||
{"R_WIN", VK_RWIN},
|
||||
{"MENU", VK_APPS},
|
||||
|
||||
// Other Keys
|
||||
// PrtSc is more important when making snapshots, therefore comment it as reserved
|
||||
//{"PRINT_SCREEN", VK_SNAPSHOT},
|
||||
{"SCROLL_LOCK", VK_SCROLL},
|
||||
{"PAUSE", VK_PAUSE},
|
||||
{"INSERT", VK_INSERT},
|
||||
{"DELETE", VK_DELETE},
|
||||
{"HOME", VK_HOME},
|
||||
{"END", VK_END},
|
||||
{"PAGE_UP", VK_PRIOR},
|
||||
{"PAGE_DOWN", VK_NEXT},
|
||||
|
||||
// Arrow Keys
|
||||
{"UPARROW", VK_UP},
|
||||
{"LEFTARROW", VK_LEFT},
|
||||
{"DOWNARROW", VK_DOWN},
|
||||
{"RIGHTARROW", VK_RIGHT},
|
||||
|
||||
// NUMPAD Keys
|
||||
{"NUM_LOCK", VK_NUMLOCK},
|
||||
{"DIVIDE", VK_DIVIDE},
|
||||
{"MULTIPLY", VK_MULTIPLY},
|
||||
{"SUBTRACT", VK_SUBTRACT},
|
||||
{"NUM7", VK_NUMPAD7},
|
||||
{"NUM8", VK_NUMPAD8},
|
||||
{"NUM9", VK_NUMPAD9},
|
||||
{"ADD", VK_ADD},
|
||||
{"NUM4", VK_NUMPAD4},
|
||||
{"NUM5", VK_NUMPAD5},
|
||||
{"NUM6", VK_NUMPAD6},
|
||||
{"NUM1", VK_NUMPAD1},
|
||||
{"NUM2", VK_NUMPAD2},
|
||||
{"NUM3", VK_NUMPAD3},
|
||||
{"NUM0", VK_NUMPAD0},
|
||||
{"DECIMAL", VK_DECIMAL},
|
||||
};
|
||||
|
||||
inline static std::map<std::string, u8> ConfigKeyboardButtons{};
|
||||
|
||||
inline static const std::map<std::string, SDL_GamepadButton> ConfigControllerButtons = {
|
||||
{"SDL_A", SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{"SDL_B", SDL_GAMEPAD_BUTTON_EAST},
|
||||
{"SDL_X", SDL_GAMEPAD_BUTTON_WEST},
|
||||
{"SDL_Y", SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{"SDL_BACK", SDL_GAMEPAD_BUTTON_BACK},
|
||||
{"SDL_GUIDE", SDL_GAMEPAD_BUTTON_GUIDE},
|
||||
{"SDL_START", SDL_GAMEPAD_BUTTON_START},
|
||||
{"SDL_LSTICK_PRESS", SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{"SDL_RSTICK_PRESS", SDL_GAMEPAD_BUTTON_RIGHT_STICK},
|
||||
{"SDL_LSHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
||||
{"SDL_RSHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
||||
{"SDL_DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||
{"SDL_DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||
{"SDL_DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||
{"SDL_DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||
{"SDL_MISC", SDL_GAMEPAD_BUTTON_MISC1},
|
||||
{"SDL_PADDLE1", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
|
||||
{"SDL_PADDLE2", SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
|
||||
{"SDL_PADDLE3", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
|
||||
{"SDL_PADDLE4", SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
|
||||
{"SDL_TOUCHPAD", SDL_GAMEPAD_BUTTON_TOUCHPAD},
|
||||
};
|
||||
inline static const std::map<std::string, SDLAxis> ConfigControllerAXIS = {
|
||||
{"SDL_LSTICK_LEFT", SDLAxis::SDL_AXIS_LEFT_LEFT}, {"SDL_LSTICK_UP", SDLAxis::SDL_AXIS_LEFT_UP}, {"SDL_LSTICK_DOWN", SDLAxis::SDL_AXIS_LEFT_DOWN},
|
||||
{"SDL_LSTICK_RIGHT", SDLAxis::SDL_AXIS_LEFT_RIGHT}, {"SDL_RSTICK_LEFT", SDLAxis::SDL_AXIS_RIGHT_LEFT}, {"SDL_RSTICK_UP", SDLAxis::SDL_AXIS_RIGHT_UP},
|
||||
{"SDL_RSTICK_DOWN", SDLAxis::SDL_AXIS_RIGHT_DOWN}, {"SDL_RSTICK_RIGHT", SDLAxis::SDL_AXIS_RIGHT_RIGHT}, {"SDL_LTRIGGER", SDLAxis::SDL_AXIS_LTRIGGER_DOWN},
|
||||
{"SDL_RTRIGGER", SDLAxis::SDL_AXIS_RTRIGGER_DOWN},
|
||||
};
|
||||
inline static const std::map<std::string, Scroll> ConfigMouseScroll = {
|
||||
{"SCROLL_UP", Scroll::MOUSE_SCROLL_UP},
|
||||
{"SCROLL_DOWN", Scroll::MOUSE_SCROLL_DOWN},
|
||||
};
|
||||
|
||||
// Singleton pattern for global access
|
||||
static ConfigManager& instance() {
|
||||
try {
|
||||
static ConfigManager instance; // Guaranteed to be destroyed, instantiated on first use
|
||||
return instance;
|
||||
} catch (std::runtime_error &e) {
|
||||
std::cerr << "[Logger] Failed to parse Default Config: " << e.what () << std::endl;
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static bool validateConfigfile(std::string path);
|
||||
|
||||
// Load configuration from a file (deserialization happens here)
|
||||
bool loadConfig();
|
||||
|
||||
// Accessor methods
|
||||
const globalConfig& getConfig() const { return config; }
|
||||
|
||||
// To access specific parts of the config
|
||||
const amauthConfig& getAmauthConfig() const { return config.amauth; }
|
||||
const patchesConfig& getPatchesConfig() const { return config.patches; }
|
||||
const emulationConfig& getEmulationConfig() const { return config.emulation; }
|
||||
const graphicsConfig& getGraphicsConfig() const { return config.graphics; }
|
||||
const audioConfig& getAudioConfig() const { return config.audio; }
|
||||
const qrConfig& getQrConfig();
|
||||
const controllerConfig& getControllerConfig() const { return config.controller; }
|
||||
const keyboardConfig& getKeyboardConfig() const { return config.keyboard; }
|
||||
const layeredfsConfig& getLayeredFsConfig() const { return config.layeredfs; }
|
||||
const loggingConfig& getLoggingConfig() const { return config.logging; }
|
||||
const keybindingConfig& getKeyBindings() const { return keyBindings; }
|
||||
|
||||
void setRes(i32 x, i32 y) {
|
||||
config.graphics.res.x = x;
|
||||
config.graphics.res.y = y;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ConfigManager();
|
||||
~ConfigManager() = default;
|
||||
|
||||
// Prevent copy/move
|
||||
ConfigManager(const ConfigManager&) = delete;
|
||||
ConfigManager& operator=(const ConfigManager&) = delete;
|
||||
|
||||
bool loadKeyBindings();
|
||||
bool updateQrConfig();
|
||||
|
||||
globalConfig config;
|
||||
keybindingConfig keyBindings;
|
||||
bool isLoaded;
|
||||
|
||||
// Mutex for thread safety (if needed)
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " <config file>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string fullPath = argv[1];
|
||||
if (!Config::ConfigManager::validateConfigfile(fullPath)) {
|
||||
std::cerr << "Config file is invalid" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Config file is valid" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
+35
-94
@@ -4,6 +4,8 @@
|
||||
#include "patches/patches.h"
|
||||
#include "poll.h"
|
||||
#include "logger.h"
|
||||
#include "banner.h"
|
||||
#include "config.h"
|
||||
#include <dbghelp.h>
|
||||
|
||||
auto gameVersion = GameVersion::UNKNOWN;
|
||||
@@ -11,35 +13,28 @@ std::vector<HMODULE> plugins;
|
||||
u64 song_data_size = 1024 * 1024 * 64;
|
||||
void *song_data;
|
||||
|
||||
std::string server = "127.0.0.1";
|
||||
std::string port = "54430";
|
||||
std::string chassisId = "284111080000";
|
||||
std::string shopId = "TAIKO ARCADE LOADER";
|
||||
std::string gameVerNum = "00.00";
|
||||
std::string countryCode = "JPN";
|
||||
char fullAddress[256] = {};
|
||||
char placeId[16] = {};
|
||||
char accessCode1[21] = "00000000000000000001";
|
||||
char accessCode2[21] = "00000000000000000002";
|
||||
char chipId1[33] = "00000000000000000000000000000001";
|
||||
char chipId2[33] = "00000000000000000000000000000002";
|
||||
bool windowed = false;
|
||||
bool autoIme = true;
|
||||
bool jpLayout = false;
|
||||
bool cursor = true;
|
||||
bool emulateUsio = true;
|
||||
bool emulateCardReader = true;
|
||||
bool emulateQr = true;
|
||||
bool acceptInvalidCards = false;
|
||||
bool localFiles = true;
|
||||
HKL currentLayout = nullptr;
|
||||
i32 xRes = 1920;
|
||||
i32 yRes = 1080;
|
||||
bool vsync = false;
|
||||
bool windowed = Config::ConfigManager::instance ().getGraphicsConfig ().windowed;
|
||||
bool autoIme = Config::ConfigManager::instance ().getKeyboardConfig ().auto_ime;
|
||||
bool jpLayout = Config::ConfigManager::instance ().getKeyboardConfig ().jp_layout;
|
||||
bool cursor = Config::ConfigManager::instance ().getGraphicsConfig ().cursor;
|
||||
bool emulateUsio = Config::ConfigManager::instance ().getEmulationConfig ().usio;
|
||||
bool emulateCardReader = Config::ConfigManager::instance ().getEmulationConfig ().card_reader;
|
||||
bool emulateQr = Config::ConfigManager::instance ().getEmulationConfig ().qr;
|
||||
bool acceptInvalidCards = Config::ConfigManager::instance ().getEmulationConfig ().accept_invalid;
|
||||
bool localFiles = Config::ConfigManager::instance ().getPatchesConfig ().local_files;
|
||||
|
||||
std::string logLevelStr = "INFO";
|
||||
bool logToFile = true;
|
||||
std::string logPath = "TaikoArcadeLoader.log";
|
||||
HKL currentLayout = nullptr;
|
||||
i32 xRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.x;
|
||||
i32 yRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.y;
|
||||
bool vsync = Config::ConfigManager::instance ().getGraphicsConfig ().vsync;
|
||||
|
||||
std::string logLevelStr = Config::ConfigManager::instance ().getLoggingConfig ().log_level.name ();
|
||||
bool logToFile = Config::ConfigManager::instance ().getLoggingConfig ().log_to_file;
|
||||
std::string logDir = Config::ConfigManager::instance ().getLoggingConfig ().log_dir;
|
||||
|
||||
HWND hGameWnd;
|
||||
FAST_HOOK (i32, ShowMouse, PROC_ADDRESS ("user32.dll", "ShowCursor"), bool) { return originalShowMouse.stdcall<i32> (true); }
|
||||
@@ -64,7 +59,7 @@ FAST_HOOK (HWND, CreateWindow, PROC_ADDRESS ("user32.dll", "CreateWindowExW"), D
|
||||
i32 X, i32 Y, i32 nWidth, i32 nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) {
|
||||
if (lpWindowName != nullptr) {
|
||||
if (wcscmp (lpWindowName, L"Taiko") == 0) {
|
||||
if (windowed) dwStyle = WS_TILEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME;
|
||||
if (Config::ConfigManager::instance ().getGraphicsConfig ().windowed) dwStyle = WS_TILEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME;
|
||||
|
||||
hGameWnd
|
||||
= originalCreateWindow.stdcall<HWND> (dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
||||
@@ -99,12 +94,12 @@ FAST_HOOK (i32, ssleay_Shutdown, PROC_ADDRESS ("ssleay32.dll", "SSL_shutdown"))
|
||||
FAST_HOOK (i64, UsbFinderInitialize, PROC_ADDRESS ("nbamUsbFinder.dll", "nbamUsbFinderInitialize")) { return 0; }
|
||||
FAST_HOOK (i64, UsbFinderRelease, PROC_ADDRESS ("nbamUsbFinder.dll", "nbamUsbFinderRelease")) { return 0; }
|
||||
FAST_HOOK (i64, UsbFinderGetSerialNumber, PROC_ADDRESS ("nbamUsbFinder.dll", "nbamUsbFinderGetSerialNumber"), i32 a1, char *a2) {
|
||||
strcpy (a2, chassisId.c_str ());
|
||||
strcpy (a2, Config::ConfigManager::instance ().getAmauthConfig ().chassis_id.value ().c_str ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
FAST_HOOK (i32, ws2_getaddrinfo, PROC_ADDRESS ("ws2_32.dll", "getaddrinfo"), const char *node, char *service, void *hints, void *out) {
|
||||
return originalws2_getaddrinfo.stdcall<i32> (server.c_str (), service, hints, out);
|
||||
return originalws2_getaddrinfo.stdcall<i32> (Config::ConfigManager::instance ().getAmauthConfig ().server.c_str (), service, hints, out);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -173,63 +168,10 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
|
||||
// Init logger for loading config
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
InitializeLogger (GetLogLevel (logLevelStr), logToFile, logPath);
|
||||
Logger::InitializeLogger (Logger::GetLogLevel (logLevelStr), logToFile, logDir);
|
||||
patches::Timer::Init ();
|
||||
|
||||
LogMessage (LogLevel::INFO, "Loading config...");
|
||||
|
||||
std::string version = "auto";
|
||||
const std::filesystem::path configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
const toml_table_t *config = config_ptr.get ();
|
||||
if (const auto amauthConfig = openConfigSection (config, "amauth")) {
|
||||
server = readConfigString (amauthConfig, "server", server);
|
||||
port = readConfigString (amauthConfig, "port", port);
|
||||
chassisId = readConfigString (amauthConfig, "chassis_id", chassisId);
|
||||
shopId = readConfigString (amauthConfig, "shop_id", shopId);
|
||||
gameVerNum = readConfigString (amauthConfig, "game_ver", gameVerNum);
|
||||
countryCode = readConfigString (amauthConfig, "country_code", countryCode);
|
||||
|
||||
std::strcat (fullAddress, server.c_str ());
|
||||
if (!port.empty ()) {
|
||||
std::strcat (fullAddress, ":");
|
||||
std::strcat (fullAddress, port.c_str ());
|
||||
}
|
||||
|
||||
std::strcat (placeId, countryCode.c_str ());
|
||||
std::strcat (placeId, "0FF0");
|
||||
}
|
||||
if (const auto patches = openConfigSection (config, "patches")) {
|
||||
version = readConfigString (patches, "version", version);
|
||||
localFiles = readConfigBool (patches, "local_files", localFiles);
|
||||
}
|
||||
if (const auto emulation = openConfigSection (config, "emulation")) {
|
||||
emulateUsio = readConfigBool (emulation, "usio", emulateUsio);
|
||||
emulateCardReader = readConfigBool (emulation, "card_reader", emulateCardReader);
|
||||
acceptInvalidCards = readConfigBool (emulation, "accept_invalid", acceptInvalidCards);
|
||||
emulateQr = readConfigBool (emulation, "qr", emulateQr);
|
||||
}
|
||||
if (const auto graphics = openConfigSection (config, "graphics")) {
|
||||
windowed = readConfigBool (graphics, "windowed", windowed);
|
||||
cursor = readConfigBool (graphics, "cursor", cursor);
|
||||
if (auto res = openConfigSection (graphics, "res")) {
|
||||
xRes = static_cast<i32> (readConfigInt (res, "x", xRes));
|
||||
yRes = static_cast<i32> (readConfigInt (res, "y", yRes));
|
||||
}
|
||||
vsync = readConfigBool (graphics, "vsync", vsync);
|
||||
}
|
||||
if (const auto keyboard = openConfigSection (config, "keyboard")) {
|
||||
autoIme = readConfigBool (keyboard, "auto_ime", autoIme);
|
||||
jpLayout = readConfigBool (keyboard, "jp_layout", jpLayout);
|
||||
}
|
||||
|
||||
if (const auto logging = openConfigSection (config, "logging")) {
|
||||
logLevelStr = readConfigString (logging, "log_level", logLevelStr);
|
||||
logToFile = readConfigBool (logging, "log_to_file", logToFile);
|
||||
logPath = readConfigString (logging, "log_path", logPath);
|
||||
}
|
||||
}
|
||||
std::string version = Config::ConfigManager::instance ().getPatchesConfig ().version.name ();
|
||||
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
|
||||
auto activeWindow = GetActiveWindow();
|
||||
@@ -251,21 +193,20 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
auto cyPhysical = devMode.dmPelsHeight;
|
||||
|
||||
// Calculate the scaling factor
|
||||
auto horizontalScale = (static_cast<double> (cxPhysical) / static_cast<double> (cxLogical));
|
||||
auto verticalScale = (static_cast<double> (cyPhysical) / static_cast<double> (cyLogical));
|
||||
auto hScale = (static_cast<double> (cxPhysical) / static_cast<double> (cxLogical));
|
||||
auto vScale = (static_cast<double> (cyPhysical) / static_cast<double> (cyLogical));
|
||||
if (windowed) {
|
||||
// Game will automatically adjust scale
|
||||
xRes = (int)(xRes / horizontalScale);
|
||||
yRes = (int)(yRes / verticalScale);
|
||||
xRes = (int)(xRes / hScale);
|
||||
yRes = (int)(yRes / vScale);
|
||||
} else {
|
||||
xRes = cxLogical;
|
||||
yRes = cyLogical;
|
||||
if (yRes * 16 > xRes * 9) yRes = (int)(xRes * 9.0 / 16.0);
|
||||
else if (yRes * 16 < xRes * 9) xRes = (int)(yRes * 16.0 / 9.0);
|
||||
}
|
||||
|
||||
LogMessage (LogLevel::INFO, "Scale Rate: x={} y={}", horizontalScale, verticalScale);
|
||||
LogMessage (LogLevel::INFO, "Boot with {} mode ({}x{})", windowed ? "window" : "fullscreen", xRes, yRes);
|
||||
Config::ConfigManager::instance ().setRes (xRes, yRes);
|
||||
LogMessage (LogLevel::INFO, "Using {} mode [{}(x{}), {}(x{})]", windowed ? "window" : "fullscreen", xRes, hScale, yRes, vScale);
|
||||
|
||||
if (autoIme) {
|
||||
currentLayout = GetKeyboardLayout (0);
|
||||
@@ -275,8 +216,6 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
}
|
||||
|
||||
// Update the logger with the level read from config file.
|
||||
InitializeLogger (GetLogLevel (logLevelStr), logToFile, logPath);
|
||||
LogMessage (LogLevel::INFO, "Application started.");
|
||||
|
||||
if (version == "auto") GetGameVersion ();
|
||||
else if (version == "JPN00") gameVersion = GameVersion::JPN00;
|
||||
@@ -288,7 +227,8 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
MessageBoxA (nullptr, "Unknown patch version", nullptr, MB_OK);
|
||||
ExitProcess (0);
|
||||
}
|
||||
LogMessage (LogLevel::INFO, "GameVersion is {}", GameVersionToString (gameVersion));
|
||||
LogMessage (LogLevel::INFO, "Using GameVersion: {}", GameVersionToString (gameVersion));
|
||||
Logger::InitLoggerHook ();
|
||||
|
||||
patches::Plugins::LoadPlugins ();
|
||||
patches::Plugins::InitVersion (gameVersion);
|
||||
@@ -299,7 +239,7 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
GetPrivateProfileStringA ("card", "accessCode2", accessCode2, accessCode2, 21, ".\\card.ini");
|
||||
GetPrivateProfileStringA ("card", "chipId2", chipId2, chipId2, 33, ".\\card.ini");
|
||||
|
||||
LogMessage (LogLevel::INFO, "==== Loading patches, please wait...");
|
||||
LogMessage (LogLevel::DEBUG, "=== Loading patches, please wait...");
|
||||
|
||||
if (windowed && cursor) INSTALL_FAST_HOOK (ShowMouse);
|
||||
INSTALL_FAST_HOOK (ExitWindows);
|
||||
@@ -344,7 +284,8 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
// patches::UnlimitSong::Init ();
|
||||
|
||||
std::chrono::duration<double> duration = std::chrono::high_resolution_clock::now() - start;
|
||||
LogMessage (LogLevel::INFO, "==== Finished Loading patches! using: {:.2f}ms", duration.count () * 1000);
|
||||
LogMessage (LogLevel::DEBUG, "=== Finished Loading patches!");
|
||||
LogMessage (LogLevel::INFO, "Taiko Starts in {:.2f}ms", duration.count () * 1000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
-109
@@ -1,115 +1,6 @@
|
||||
#include <codecvt>
|
||||
#include "helpers.h"
|
||||
|
||||
static void
|
||||
toml_myfree (void *p) {
|
||||
if (p) free (p);
|
||||
}
|
||||
|
||||
toml_table_t *
|
||||
openConfig (const std::filesystem::path &path) {
|
||||
if (!exists (path) || !path.has_filename ()) {
|
||||
LogMessage (LogLevel::WARN, std::string (path.string ()) + ": file does not exist");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::ifstream stream (path);
|
||||
if (!stream.is_open ()) {
|
||||
LogMessage (LogLevel::WARN, ("Could not open " + std::string (path.string ())).c_str ());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
stream.seekg (0, stream.end);
|
||||
const size_t length = stream.tellg ();
|
||||
stream.seekg (0, stream.beg);
|
||||
|
||||
const auto buf = static_cast<char *> (calloc (length + 1, sizeof (char)));
|
||||
stream.read (buf, length);
|
||||
|
||||
char errorBuffer[200];
|
||||
toml_table_t *config = toml_parse (buf, errorBuffer, 200);
|
||||
stream.close ();
|
||||
free (buf);
|
||||
|
||||
if (!config) {
|
||||
LogMessage (LogLevel::WARN, (path.string () + ": " + errorBuffer).c_str ());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
toml_table_t *
|
||||
openConfigSection (const toml_table_t *config, const std::string §ionName) {
|
||||
toml_table_t *section = toml_table_in (config, sectionName.c_str ());
|
||||
if (!section) {
|
||||
LogMessage (LogLevel::ERROR, ("Cannot find section " + sectionName).c_str ());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
bool
|
||||
readConfigBool (const toml_table_t *table, const std::string &key, const bool notFoundValue) {
|
||||
const auto [ok, u] = toml_bool_in (table, key.c_str ());
|
||||
if (!ok) {
|
||||
LogMessage (LogLevel::WARN, ("Could not find Boolean named " + key).c_str ());
|
||||
return notFoundValue;
|
||||
}
|
||||
return static_cast<bool> (u.b);
|
||||
}
|
||||
|
||||
i64
|
||||
readConfigInt (const toml_table_t *table, const std::string &key, const i64 notFoundValue) {
|
||||
const auto [ok, u] = toml_int_in (table, key.c_str ());
|
||||
if (!ok) {
|
||||
LogMessage (LogLevel::WARN, ("Could not find Int named " + key).c_str ());
|
||||
return notFoundValue;
|
||||
}
|
||||
return u.i;
|
||||
}
|
||||
|
||||
double
|
||||
readConfigDouble (const toml_table_t *table, const std::string &key, const double notFoundValue) {
|
||||
const auto [ok, u] = toml_double_in (table, key.c_str ());
|
||||
if (!ok) {
|
||||
LogMessage (LogLevel::WARN, ("Could not find Int named " + key).c_str ());
|
||||
return notFoundValue;
|
||||
}
|
||||
return u.d;
|
||||
}
|
||||
|
||||
std::string
|
||||
readConfigString (const toml_table_t *table, const std::string &key, const std::string ¬FoundValue) {
|
||||
const auto [ok, u] = toml_string_in (table, key.c_str ());
|
||||
if (!ok) {
|
||||
LogMessage (LogLevel::WARN, ("Could not find String named " + key).c_str ());
|
||||
return notFoundValue;
|
||||
}
|
||||
std::string str = u.s;
|
||||
toml_myfree (u.s);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<i64>
|
||||
readConfigIntArray (const toml_table_t *table, const std::string &key, std::vector<i64> notFoundValue) {
|
||||
const toml_array_t *array = toml_array_in (table, key.c_str ());
|
||||
if (!array) {
|
||||
LogMessage (LogLevel::WARN, ("Could not find int Array named " + key).c_str ());
|
||||
return notFoundValue;
|
||||
}
|
||||
|
||||
std::vector<i64> ret;
|
||||
for (int i = 0;; i++) {
|
||||
auto [ok, u] = toml_int_at (array, i);
|
||||
if (!ok) break;
|
||||
ret.push_back (u.i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::wstring
|
||||
replace (const std::wstring orignStr, const std::wstring &oldStr, const std::wstring &newStr) {
|
||||
size_t pos = 0;
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
// ReSharper disable once CppUnusedIncludeDirective
|
||||
#include <MinHook.h>
|
||||
#include <string>
|
||||
#include <toml.h>
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include "constants.h"
|
||||
#include "logger.h"
|
||||
@@ -168,13 +166,6 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr);
|
||||
#define round(num) ((num > 0) ? (int)(num + 0.5) : (int)(num - 0.5))
|
||||
#define timestamp() (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ())
|
||||
|
||||
toml_table_t *openConfig (const std::filesystem::path &path);
|
||||
toml_table_t *openConfigSection (const toml_table_t *config, const std::string §ionName);
|
||||
bool readConfigBool (const toml_table_t *table, const std::string &key, bool notFoundValue);
|
||||
i64 readConfigInt (const toml_table_t *table, const std::string &key, i64 notFoundValue);
|
||||
double readConfigDouble (const toml_table_t *table, const std::string &key, const double notFoundValue);
|
||||
std::string readConfigString (const toml_table_t *table, const std::string &key, const std::string ¬FoundValue);
|
||||
std::vector<i64> readConfigIntArray (const toml_table_t *table, const std::string &key, std::vector<i64> notFoundValue);
|
||||
std::wstring replace (const std::wstring orignStr, const std::wstring &oldStr, const std::wstring &newStr);
|
||||
std::string replace (const std::string orignStr, const std::string &oldStr, const std::string &newStr);
|
||||
const char *GameVersionToString (GameVersion version);
|
||||
|
||||
+225
-93
@@ -1,113 +1,245 @@
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include "logger.h"
|
||||
#include "config.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdarg>
|
||||
#include <memory>
|
||||
|
||||
static Logger *loggerInstance = nullptr;
|
||||
void *consoleHandle = nullptr;
|
||||
std::mutex logMutex; // Mutex for thread-safe logging
|
||||
extern GameVersion gameVersion;
|
||||
|
||||
char timeStr[64];
|
||||
time_t rawTime;
|
||||
tm *timeInfo;
|
||||
SYSTEMTIME systemTime;
|
||||
bool s_logMethodName = Config::ConfigManager::instance ().getLoggingConfig ().log_method_name;
|
||||
bool s_logFullSource = Config::ConfigManager::instance ().getLoggingConfig ().log_full_source;
|
||||
|
||||
// Static member definitions
|
||||
LogLevel Logger::s_logLevel = LogLevel::NONE;
|
||||
void* Logger::s_consoleHandle = nullptr;
|
||||
bool Logger::s_isInitialized = false;
|
||||
std::fstream* Logger::s_logFile = nullptr;
|
||||
std::mutex Logger::s_logMutex;
|
||||
|
||||
bool loggerInited = false;
|
||||
|
||||
// FAST_HOOK_DYNAMIC (int, TaikoPrintf, const char *format, ...) {
|
||||
// va_list args;
|
||||
// va_start (args, format);
|
||||
// int requiredSize = vsnprintf (nullptr, 0, format, args) + 1; // +1 for null terminator
|
||||
// std::unique_ptr<char[]> buffer (new char[requiredSize]);
|
||||
// vsnprintf (buffer.get (), requiredSize, format, args);
|
||||
// Logger::LogMessageHandler ("printf", "Taiko.exe", -1, LogLevel::GAME, buffer.get ());
|
||||
// va_end (args);
|
||||
// return requiredSize;
|
||||
// }
|
||||
|
||||
// i64 coutVal = 0;
|
||||
// FAST_HOOK_DYNAMIC (i64 *, TaikoPrint, i64 *a1, const char *msg) {
|
||||
// if ((i64) a1 != coutVal) originalTaikoPrint.call<i64 *> (a1, msg);
|
||||
// Logger::LogMessageHandler ("std::cout", "Taiko.exe", -1, LogLevel::GAME, msg);
|
||||
// return a1;
|
||||
// }
|
||||
|
||||
void
|
||||
InitializeLogger (const LogLevel level, const bool logToFile, const std::string& logPath) {
|
||||
if (loggerInstance == nullptr) {
|
||||
loggerInstance = static_cast<Logger *> (malloc (sizeof (Logger)));
|
||||
if (consoleHandle == nullptr) consoleHandle = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
}
|
||||
Logger::InitLoggerHook () {
|
||||
if (loggerInited) return;
|
||||
loggerInited = true;
|
||||
// switch (gameVersion) {
|
||||
// case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: default: break;
|
||||
// case GameVersion::JPN39: {
|
||||
// coutVal = *(i64 *)ASLR (0x1408CCBF8);
|
||||
// INSTALL_FAST_HOOK_DYNAMIC (TaikoPrintf, ASLR (0x1400D3EE0));
|
||||
// INSTALL_FAST_HOOK_DYNAMIC (TaikoPrint, ASLR (0x14004B4F0));
|
||||
// } break;
|
||||
// }
|
||||
}
|
||||
|
||||
loggerInstance->logLevel = level;
|
||||
static std::string
|
||||
ConvertWideToUtf8(const wchar_t* wstr) {
|
||||
if (!wstr) return {};
|
||||
std::wstring ws (wstr);
|
||||
return {ws.begin (), ws.end ()};
|
||||
}
|
||||
|
||||
void
|
||||
Logger::InitializeLogger(const LogLevel level, const bool logToFile, std::string logDir) {
|
||||
if (s_isInitialized) return;
|
||||
s_isInitialized = true;
|
||||
|
||||
s_logLevel = level;
|
||||
if (s_consoleHandle == nullptr) s_consoleHandle = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
|
||||
if (logToFile) {
|
||||
loggerInstance->logFile = fopen (logPath.c_str (), "w"); // Open in write mode
|
||||
if (!loggerInstance->logFile) LogMessage (LogLevel::WARN, std::string ("Failed to open TaikoArcadeLoader.log for writing."));
|
||||
} else loggerInstance->logFile = nullptr; // No file logging
|
||||
}
|
||||
try {
|
||||
const std::filesystem::path logsDir ("logs");
|
||||
if (!std::filesystem::exists (logsDir)) std::filesystem::create_directories (logsDir);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[Logger] Failed to create logs directory: " << e.what () << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const char *format, ...) {
|
||||
// Return if no logger or log level is too high
|
||||
if (loggerInstance == nullptr || messageLevel > loggerInstance->logLevel) return;
|
||||
// Construct a daily log filename
|
||||
const auto now = std::chrono::system_clock::now ();
|
||||
const auto timeT = std::chrono::system_clock::to_time_t (now);
|
||||
std::tm localTm = {};
|
||||
localtime_s (&localTm, &timeT);
|
||||
|
||||
// Lock for thread safety
|
||||
std::lock_guard lock (logMutex);
|
||||
char dateFilename[256];
|
||||
// Example format: "TaikoArcadeLoader-YYYYMMDD.log"
|
||||
std::strftime (dateFilename, sizeof (dateFilename), "TaikoArcadeLoader-%Y%m%d.log", &localTm);
|
||||
|
||||
// Format the user-provided message
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
int requiredSize = vsnprintf (nullptr, 0, format, args) + 1; // +1 for null terminator
|
||||
std::unique_ptr<char[]> buffer (new char[requiredSize]); // Allocate buffer dynamically
|
||||
vsnprintf (buffer.get (), requiredSize, format, args); // Format the string
|
||||
std::string formattedMessage (buffer.get ()); // Convert to std::string
|
||||
va_end (args);
|
||||
|
||||
// Determine log type string
|
||||
std::string logType = GetLogLevelString (messageLevel);
|
||||
|
||||
// Shrink function name by regex
|
||||
std::string short_function (function);
|
||||
std::regex re(R"(.*? (([\w<>]+::)*[\w]+( [()<>+-]+)?)\(\w+.*?\))");
|
||||
short_function = std::regex_replace (short_function, re, "$1");
|
||||
|
||||
// Remove the absolute path of the build dir
|
||||
constexpr std::string_view build_dir = XSTRING (SOURCE_ROOT);
|
||||
std::string_view filename = codeFile;
|
||||
filename.remove_prefix (build_dir.size ());
|
||||
|
||||
// Get current time and milliseconds
|
||||
SYSTEMTIME systemTime;
|
||||
GetSystemTime (&systemTime);
|
||||
time_t rawTime = time (nullptr);
|
||||
tm *timeInfo = localtime (&rawTime);
|
||||
std::ostringstream timeStamp;
|
||||
timeStamp << std::put_time (timeInfo, "%Y/%m/%d %H:%M:%S") << "." << std::setw (3) << std::setfill ('0') << systemTime.wMilliseconds;
|
||||
|
||||
// Construct the log message
|
||||
std::ostringstream logStream;
|
||||
logStream << short_function << " (" << filename << ":" << codeLine << "): " << formattedMessage;
|
||||
std::string logMessage = logStream.str ();
|
||||
|
||||
// Print the log message
|
||||
std::cout << "[" << timeStamp.str () << "] "; // Timestamp
|
||||
SetConsoleTextAttribute (consoleHandle, GetLogLevelColor (messageLevel)); // Set Level color
|
||||
std::cout << logType; // Level
|
||||
if (messageLevel != LogLevel::ERROR) {
|
||||
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); // Reset console color
|
||||
if (!logDir.ends_with ("/")) logDir += "/";
|
||||
const std::string fullLogPath = logDir + dateFilename;
|
||||
s_logFile = new std::fstream (fullLogPath.c_str (), std::ios::out | std::ios::app);
|
||||
if (!s_logFile->is_open ()) {
|
||||
std::cerr << "[Logger] Failed to open " << fullLogPath << " for writing.\n";
|
||||
s_logFile = nullptr;
|
||||
}
|
||||
}
|
||||
std::cout << logMessage << std::endl; // Log message
|
||||
if (messageLevel == LogLevel::ERROR) {
|
||||
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); // Reset console color
|
||||
}
|
||||
std::cout.flush (); // Flush to ensure immediate writing
|
||||
|
||||
if (loggerInstance->logFile != nullptr) {
|
||||
fprintf (loggerInstance->logFile, "[%s] %s%s\n", timeStamp.str ().c_str (), logType.c_str (), logMessage.c_str ());
|
||||
fflush (loggerInstance->logFile); // Flush to ensure immediate writing
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogMessageHandler (const char *function, const char *codeFile, const int codeLine, const LogLevel messageLevel, const wchar_t *format, ...) {
|
||||
const std::string utf8Message = ConvertWideToUtf8 (format); // Convert wide string to UTF-8
|
||||
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
LogMessageHandler (function, codeFile, codeLine, messageLevel, utf8Message.c_str (), args); // Delegate to the original handler
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
bool
|
||||
EnableLogging (LogLevel messageLevel) {
|
||||
return loggerInstance != nullptr && messageLevel <= loggerInstance->logLevel;
|
||||
Logger::GuardianOutput (LogLevel messageLevel) {
|
||||
return !s_isInitialized || messageLevel > s_logLevel;
|
||||
}
|
||||
|
||||
void
|
||||
CleanupLogger () {
|
||||
if (loggerInstance != nullptr) {
|
||||
if (loggerInstance->logFile) fclose (loggerInstance->logFile);
|
||||
free (loggerInstance);
|
||||
loggerInstance = nullptr;
|
||||
Logger::LogMessageHandler (const char* function, const char* codeFile, int codeLine, LogLevel messageLevel, const char* format, ...) {
|
||||
// Return if logger uninitialized or messageLevel is more verbose than the set level
|
||||
if (!s_isInitialized || messageLevel > s_logLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock (s_logMutex);
|
||||
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
int requiredSize = vsnprintf (nullptr, 0, format, args) + 1; // +1 for null terminator
|
||||
std::unique_ptr<char[]> buffer (new char[requiredSize]);
|
||||
vsnprintf (buffer.get (), requiredSize, format, args);
|
||||
std::string formattedMessage (buffer.get());
|
||||
while (formattedMessage.ends_with ("\n")) {
|
||||
formattedMessage = formattedMessage.substr (0, formattedMessage.size () - 1);
|
||||
}
|
||||
va_end (args);
|
||||
|
||||
std::string logType = Logger::GetLogLevelString(messageLevel);
|
||||
|
||||
std::string short_function (function);
|
||||
std::regex re (R"(.*? (([\w<>]+::)*[\w]+( [()<>+-]+)?)\(\w+.*?\))");
|
||||
short_function = std::regex_replace (short_function, re, "$1");
|
||||
|
||||
SYSTEMTIME systemTime;
|
||||
GetSystemTime (&systemTime);
|
||||
time_t rawTime = time (nullptr);
|
||||
tm* timeInfo = localtime (&rawTime);
|
||||
|
||||
std::ostringstream timeStamp;
|
||||
timeStamp << std::put_time (timeInfo, "%Y-%m-%d %H:%M:%S") << "."
|
||||
<< std::setw (3) << std::setfill ('0') << systemTime.wMilliseconds;
|
||||
|
||||
// Construct the log message
|
||||
std::ostringstream descStream;
|
||||
if (s_logMethodName) descStream << short_function << " ";
|
||||
if (s_logFullSource) {
|
||||
constexpr std::string_view build_dir = XSTRING (SOURCE_ROOT);
|
||||
std::string_view filename = codeFile;
|
||||
filename.remove_prefix (build_dir.size ());
|
||||
descStream << "(" << filename << ":" << codeLine << "): ";
|
||||
} else {
|
||||
std::string filename = std::string (codeFile);
|
||||
if (size_t begin = filename.find_last_of ("/\\"); begin != std::string::npos) {
|
||||
filename = filename.substr (begin + 1, filename.length ());
|
||||
}
|
||||
descStream << "(" << std::format("{: >20}", std::format("{}:{}", filename, codeLine)) << "): ";
|
||||
}
|
||||
std::string descMessage = descStream.str();
|
||||
|
||||
// Print to console
|
||||
std::cout << "[" << timeStamp.str() << "] ";
|
||||
SetConsoleTextAttribute (s_consoleHandle, Logger::GetLogLevelColor(messageLevel));
|
||||
std::cout << logType;
|
||||
SetConsoleTextAttribute (s_consoleHandle, FOREGROUND_INTENSITY);
|
||||
std::cout << descMessage;
|
||||
if (messageLevel == LogLevel::WARN || messageLevel == LogLevel::ERROR) {
|
||||
SetConsoleTextAttribute (s_consoleHandle, Logger::GetLogLevelColor(messageLevel));
|
||||
std::cout << formattedMessage << std::endl;
|
||||
SetConsoleTextAttribute (s_consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
} else {
|
||||
SetConsoleTextAttribute (s_consoleHandle, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
|
||||
std::cout << formattedMessage << std::endl;
|
||||
}
|
||||
std::cout.flush ();
|
||||
|
||||
if (s_logFile != nullptr) {
|
||||
*s_logFile << "[" << timeStamp.str () << "] " << logType << descMessage << formattedMessage << std::endl;
|
||||
s_logFile->flush ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Logger::LogMessageHandler (const char* function, const char* codeFile, int codeLine, LogLevel messageLevel, const wchar_t* format, ...) {
|
||||
const std::string utf8Message = ConvertWideToUtf8 (format);
|
||||
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
Logger::LogMessageHandler (function, codeFile, codeLine, messageLevel, utf8Message.c_str(), args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
void
|
||||
Logger::CleanupLogger () {
|
||||
if (s_isInitialized) {
|
||||
if (s_logFile) {
|
||||
s_logFile->close ();
|
||||
s_logFile = nullptr;
|
||||
}
|
||||
s_isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
LogLevel
|
||||
Logger::GetLogLevel (const std::string& logLevelStr) {
|
||||
if (logLevelStr == "DEBUG") return LogLevel::DEBUG;
|
||||
if (logLevelStr == "INFO") return LogLevel::INFO;
|
||||
if (logLevelStr == "WARN") return LogLevel::WARN;
|
||||
if (logLevelStr == "ERROR") return LogLevel::ERROR;
|
||||
if (logLevelStr == "GAME") return LogLevel::GAME;
|
||||
if (logLevelStr == "HOOKS") return LogLevel::HOOKS;
|
||||
return LogLevel::NONE;
|
||||
}
|
||||
|
||||
std::string
|
||||
Logger::GetLogLevelString (const LogLevel messageLevel) {
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG: return "DEBUG: ";
|
||||
case LogLevel::INFO: return "INFO : ";
|
||||
case LogLevel::WARN: return "WARN : ";
|
||||
case LogLevel::ERROR: return "ERROR: ";
|
||||
case LogLevel::HOOKS: return "HOOKS: ";
|
||||
case LogLevel::GAME: return "GAME : ";
|
||||
default: return "NONE : ";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Logger::GetLogLevelColor(const LogLevel messageLevel) {
|
||||
// Colors: https://i.sstatic.net/ZG625.png
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG:
|
||||
return FOREGROUND_BLUE | FOREGROUND_INTENSITY; // Pale Blue
|
||||
case LogLevel::INFO:
|
||||
return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // Pale Green
|
||||
case LogLevel::WARN:
|
||||
return FOREGROUND_RED | FOREGROUND_GREEN; // Bright Yellow
|
||||
case LogLevel::ERROR:
|
||||
return FOREGROUND_RED; // Bright RED
|
||||
case LogLevel::HOOKS:
|
||||
return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; // Pale Purple
|
||||
case LogLevel::GAME:
|
||||
return FOREGROUND_BLUE | FOREGROUND_RED; // Purple
|
||||
default:
|
||||
return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
|
||||
+62
-82
@@ -4,120 +4,100 @@
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <wincon.h>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
#define STRING(x) #x
|
||||
#define XSTRING(x) STRING (x)
|
||||
|
||||
enum class LogLevel {
|
||||
NONE = 0,
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
ERROR,
|
||||
#endif
|
||||
WARN,
|
||||
INFO,
|
||||
GAME,
|
||||
DEBUG,
|
||||
HOOKS
|
||||
};
|
||||
|
||||
/**
|
||||
* Logger Struct Used to Store Logging Preferences and State
|
||||
*/
|
||||
typedef struct {
|
||||
LogLevel logLevel;
|
||||
FILE *logFile;
|
||||
} Logger;
|
||||
class Logger {
|
||||
public:
|
||||
static void InitLoggerHook ();
|
||||
|
||||
/* Initializes a global Logger instance. */
|
||||
void InitializeLogger (LogLevel level, bool logToFile, const std::string& logPath);
|
||||
static void InitializeLogger (LogLevel level, bool logToFile, std::string logDir);
|
||||
|
||||
void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const char *format, ...);
|
||||
void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const wchar_t *format, ...);
|
||||
static bool GuardianOutput (LogLevel messageLevel);
|
||||
|
||||
bool EnableLogging (LogLevel level);
|
||||
static void LogMessageHandler (const char* function, const char* codeFile, int codeLine, LogLevel messageLevel, const char* format, ...);
|
||||
|
||||
static void LogMessageHandler (const char* function, const char* codeFile, int codeLine, LogLevel messageLevel, const wchar_t* format, ...);
|
||||
|
||||
static void CleanupLogger ();
|
||||
|
||||
static LogLevel GetLogLevel (const std::string& logLevelStr);
|
||||
|
||||
static std::string GetLogLevelString (LogLevel messageLevel);
|
||||
|
||||
static int GetLogLevelColor (LogLevel messageLevel);
|
||||
|
||||
private:
|
||||
// Private constructor to disallow instantiation
|
||||
Logger() = default;
|
||||
|
||||
static LogLevel s_logLevel;
|
||||
static std::fstream* s_logFile;
|
||||
static void* s_consoleHandle;
|
||||
static std::mutex s_logMutex;
|
||||
static bool s_isInitialized;
|
||||
};
|
||||
|
||||
/* *
|
||||
* Logs a message with file and line information, if the log level permits.
|
||||
*
|
||||
* Use template magic to replace macros and get proper typing support...
|
||||
*/
|
||||
template <typename... Args>
|
||||
struct LogMessage {
|
||||
LogMessage (const LogLevel level, const std::string_view format, Args &&...args,
|
||||
const std::source_location &loc = std::source_location::current ()) {
|
||||
if (!EnableLogging (level)) return;
|
||||
std::string formatted_message = std::vformat(std::string(format), std::make_format_args(args...));
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ());
|
||||
LogMessage (const LogLevel level, const std::string_view format, Args&&... args,
|
||||
const std::source_location& loc = std::source_location::current()) {
|
||||
if (Logger::GuardianOutput (level)) return;
|
||||
std::string formatted_message =
|
||||
std::vformat(std::string(format), std::make_format_args(args...));
|
||||
|
||||
Logger::LogMessageHandler(loc.function_name(), loc.file_name(), loc.line(), level, formatted_message.c_str());
|
||||
}
|
||||
|
||||
LogMessage (const LogLevel level, const std::wstring_view format, Args &&...args,
|
||||
const std::source_location &loc = std::source_location::current ()) {
|
||||
if (!EnableLogging (level)) return;
|
||||
std::wstring formatted_message = std::vformat(std::wstring(format), std::make_wformat_args(args...));
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ());
|
||||
LogMessage (const LogLevel level, const std::wstring_view format, Args&&... args,
|
||||
const std::source_location& loc = std::source_location::current()) {
|
||||
if (Logger::GuardianOutput (level)) return;
|
||||
std::wstring formatted_message =
|
||||
std::vformat(std::wstring(format), std::make_wformat_args(args...));
|
||||
|
||||
Logger::LogMessageHandler(loc.function_name(), loc.file_name(), loc.line(), level, formatted_message.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
/* *
|
||||
* Logs a message with file and line information, if the log level permits.
|
||||
*/
|
||||
template <>
|
||||
struct LogMessage<void> {
|
||||
LogMessage (const LogLevel level, const std::string_view format, const std::source_location &loc = std::source_location::current ()) {
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, format.data ());
|
||||
LogMessage(const LogLevel level, const std::string_view format,
|
||||
const std::source_location& loc = std::source_location::current()) {
|
||||
if (Logger::GuardianOutput (level)) return;
|
||||
Logger::LogMessageHandler(loc.function_name(), loc.file_name(), loc.line(), level, format.data());
|
||||
}
|
||||
|
||||
LogMessage (const LogLevel level, const std::wstring_view format, const std::source_location &loc = std::source_location::current ()) {
|
||||
LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, format.data ());
|
||||
LogMessage(const LogLevel level, const std::wstring_view format,
|
||||
const std::source_location& loc = std::source_location::current()) {
|
||||
if (Logger::GuardianOutput (level)) return;
|
||||
Logger::LogMessageHandler(loc.function_name(), loc.file_name(), loc.line(), level, format.data());
|
||||
}
|
||||
};
|
||||
|
||||
LogMessage (LogLevel level, std::string_view format) -> LogMessage<void>;
|
||||
LogMessage (LogLevel level, std::wstring_view format) -> LogMessage<void>;
|
||||
LogMessage(LogLevel level, std::string_view format) -> LogMessage<void>;
|
||||
LogMessage(LogLevel level, std::wstring_view format) -> LogMessage<void>;
|
||||
|
||||
template <typename... Args>
|
||||
LogMessage (LogLevel level, std::string_view format, Args &&...ts) -> LogMessage<Args...>;
|
||||
LogMessage(LogLevel level, std::string_view format, Args&&... ts) -> LogMessage<Args...>;
|
||||
|
||||
template <typename... Args>
|
||||
LogMessage (LogLevel level, std::wstring_view format, Args &&...ts) -> LogMessage<Args...>;
|
||||
|
||||
/* Converts a string to a LogLevel type. */
|
||||
inline LogLevel
|
||||
GetLogLevel (const std::string &logLevelStr) {
|
||||
if (logLevelStr == "DEBUG") return LogLevel::DEBUG;
|
||||
else if (logLevelStr == "INFO") return LogLevel::INFO;
|
||||
else if (logLevelStr == "WARN") return LogLevel::WARN;
|
||||
else if (logLevelStr == "ERROR") return LogLevel::ERROR;
|
||||
else if (logLevelStr == "HOOKS") return LogLevel::HOOKS;
|
||||
return LogLevel::NONE;
|
||||
}
|
||||
|
||||
/* Converts a LogLevel type to a string for logging. */
|
||||
inline std::string
|
||||
GetLogLevelString (LogLevel messageLevel) {
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG: return "DEBUG: ";
|
||||
case LogLevel::INFO: return "INFO: ";
|
||||
case LogLevel::WARN: return "WARN: ";
|
||||
case LogLevel::ERROR: return "ERROR: ";
|
||||
case LogLevel::HOOKS: return "HOOKS: ";
|
||||
default: return "NONE: ";
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts a LogLevel type to an int for colors display in the console. */
|
||||
inline int
|
||||
GetLogLevelColor (const LogLevel messageLevel) {
|
||||
// Colors: https://i.sstatic.net/ZG625.png
|
||||
switch (messageLevel) {
|
||||
case LogLevel::DEBUG: return FOREGROUND_BLUE | FOREGROUND_INTENSITY; // Pale Blue
|
||||
case LogLevel::INFO: return FOREGROUND_GREEN | FOREGROUND_INTENSITY; // Pale Green
|
||||
case LogLevel::WARN: return FOREGROUND_RED | FOREGROUND_GREEN; // Bright Yellow
|
||||
case LogLevel::ERROR: return FOREGROUND_RED; // Bright RED
|
||||
case LogLevel::HOOKS: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY; // Pale Purple
|
||||
default: return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleans up the logger, closing files if necessary. */
|
||||
void CleanupLogger ();
|
||||
LogMessage(LogLevel level, std::wstring_view format, Args&&... ts) -> LogMessage<Args...>;
|
||||
|
||||
+20
-20
@@ -1,22 +1,22 @@
|
||||
#include <winsock2.h>
|
||||
#include "helpers.h"
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ws2tcpip.h>
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
* Reference: https://gitea.tendokyu.moe/Hay1tsme/bananatools/src/branch/master/amcus/iauth.c
|
||||
* https://github.com/BroGamer4256/TaikoArcadeLoader/blob/master/plugins/amauth/dllmain.cpp
|
||||
*/
|
||||
|
||||
extern std::string server;
|
||||
extern std::string chassisId;
|
||||
extern std::string shopId;
|
||||
extern std::string gameVerNum;
|
||||
extern std::string countryCode;
|
||||
extern char fullAddress[256];
|
||||
extern char placeId[16];
|
||||
static std::string server = Config::ConfigManager::instance ().getAmauthConfig ().server;
|
||||
static std::string chassisId = Config::ConfigManager::instance ().getAmauthConfig ().chassis_id.value ();
|
||||
static std::string shopId = Config::ConfigManager::instance ().getAmauthConfig ().shop_id;
|
||||
static std::string gameVerNum = Config::ConfigManager::instance ().getAmauthConfig ().game_ver;
|
||||
static std::string countryCode = Config::ConfigManager::instance ().getAmauthConfig ().country_code;
|
||||
static std::string fullAddress = Config::ConfigManager::instance ().getAmauthConfig ().full_address();
|
||||
static std::string placeId = Config::ConfigManager::instance ().getAmauthConfig ().place_id();
|
||||
|
||||
namespace patches::AmAuth {
|
||||
|
||||
@@ -379,10 +379,10 @@ public:
|
||||
strcpy_s (version->game_id, "SBWY");
|
||||
strcpy_s (version->game_ver, "12.20");
|
||||
strcpy_s (version->game_cd, "S121");
|
||||
strcpy_s (version->cacfg_game_ver, gameVerNum.c_str ());
|
||||
strcpy_s (version->cacfg_game_ver, sizeof(version->cacfg_game_ver), gameVerNum.c_str ());
|
||||
strcpy_s (version->game_board_type, "0");
|
||||
strcpy_s (version->game_board_id, "PCB");
|
||||
strcpy_s (version->auth_url, fullAddress);
|
||||
strcpy_s (version->auth_url, sizeof(version->auth_url), fullAddress.c_str ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -392,11 +392,11 @@ public:
|
||||
|
||||
virtual i32 IAuth_GetAuthServerResp (amcus_auth_server_resp_t *resp) {
|
||||
memset (resp, 0, sizeof (*resp));
|
||||
strcpy_s (resp->uri, fullAddress);
|
||||
strcpy_s (resp->host, fullAddress);
|
||||
strcpy_s (resp->uri, sizeof(resp->uri) , fullAddress.c_str ());
|
||||
strcpy_s (resp->host, sizeof(resp->host), fullAddress.c_str ());
|
||||
|
||||
strcpy_s (resp->shop_name, shopId.c_str ());
|
||||
strcpy_s (resp->shop_nickname, shopId.c_str ());
|
||||
strcpy_s (resp->shop_name, sizeof(resp->shop_name), shopId.c_str ());
|
||||
strcpy_s (resp->shop_nickname, sizeof(resp->shop_nickname), shopId.c_str ());
|
||||
|
||||
strcpy_s (resp->region0, "01035");
|
||||
|
||||
@@ -404,9 +404,9 @@ public:
|
||||
strcpy_s (resp->region_name1, "X");
|
||||
strcpy_s (resp->region_name2, "Y");
|
||||
strcpy_s (resp->region_name3, "Z");
|
||||
strcpy_s (resp->place_id, placeId);
|
||||
strcpy_s (resp->place_id, sizeof(resp->place_id), placeId.c_str ());
|
||||
strcpy_s (resp->setting, "");
|
||||
strcpy_s (resp->country, countryCode.c_str ());
|
||||
strcpy_s (resp->country, sizeof(resp->country), countryCode.c_str ());
|
||||
strcpy_s (resp->timezone, "+0900");
|
||||
strcpy_s (resp->res_class, "PowerOnResponseVer3");
|
||||
return 0;
|
||||
@@ -424,7 +424,7 @@ public:
|
||||
strcpy_s (arr->shop_name_en, sizeof (arr->shop_name_en), shopId.c_str ());
|
||||
strcpy_s (arr->shop_nickname, sizeof (arr->shop_nickname), shopId.c_str ());
|
||||
strcpy_s (arr->shop_nickname_en, sizeof (arr->shop_nickname_en), shopId.c_str ());
|
||||
strcpy_s (arr->place_id, sizeof (arr->place_id), placeId);
|
||||
strcpy_s (arr->place_id, sizeof (arr->place_id), placeId.c_str ());
|
||||
strcpy_s (arr->country_cd, sizeof (arr->country_cd), countryCode.c_str ());
|
||||
|
||||
strcpy_s (arr->area0, sizeof (arr->area0), "008");
|
||||
@@ -447,8 +447,8 @@ public:
|
||||
|
||||
strcpy_s (arr->url_charge, sizeof (arr->url_charge), "http://127.0.0.1/charge/");
|
||||
strcpy_s (arr->url_file, sizeof (arr->url_file), "http://127.0.0.1/file/");
|
||||
strcpy_s (arr->url_url1, sizeof (arr->url_url1), fullAddress);
|
||||
strcpy_s (arr->url_url2, sizeof (arr->url_url2), fullAddress);
|
||||
strcpy_s (arr->url_url1, sizeof (arr->url_url1), fullAddress.c_str ());
|
||||
strcpy_s (arr->url_url2, sizeof (arr->url_url2), fullAddress.c_str ());
|
||||
strcpy_s (arr->url_url3, sizeof (arr->url_url3), "http://127.0.0.1/url3/");
|
||||
return 0;
|
||||
}
|
||||
@@ -549,7 +549,7 @@ CoCreateInstanceHook (const IID *const rclsid, const LPUNKNOWN pUnkOuter, const
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init AmAuth patches");
|
||||
LogMessage (LogLevel::DEBUG, "Init AmAuth patches");
|
||||
|
||||
auto whereCoCreateInstance = GetProcAddress (LoadLibraryW (L"ole32.dll"), "CoCreateInstance");
|
||||
originalCoCreateInstanceHook = safetyhook::create_inline ((void *)whereCoCreateInstance, CoCreateInstanceHook);
|
||||
|
||||
+14
-21
@@ -1,6 +1,7 @@
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches.h"
|
||||
#include "config.h"
|
||||
#include "../Windows/MinimumLatencyAudioClient.h"
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
@@ -19,10 +20,10 @@ typedef struct nusc_init_config {
|
||||
void *wasapi_audioSes;
|
||||
} nusc_init_config_t;
|
||||
|
||||
bool real = true;
|
||||
bool wasapiShared = true;
|
||||
bool asio = false;
|
||||
std::string asioDriver;
|
||||
bool wasapiShared = Config::ConfigManager::instance ().getAudioConfig ().wasapi_shared;
|
||||
bool asio = Config::ConfigManager::instance ().getAudioConfig ().asio;
|
||||
std::string asioDriver = Config::ConfigManager::instance ().getAudioConfig ().asio_driver;
|
||||
bool real = Config::ConfigManager::instance ().getAudioConfig ().real;
|
||||
|
||||
float volumeRate = 0.0f;
|
||||
|
||||
@@ -54,7 +55,7 @@ FAST_HOOK_DYNAMIC (u64, NuscBusVolume, u64 a1, u64 a2, float a3) {
|
||||
}
|
||||
|
||||
void
|
||||
SetVolumeRate (float rate) {
|
||||
SetVolumeRate (const float rate) {
|
||||
volumeRate = rate;
|
||||
}
|
||||
|
||||
@@ -67,28 +68,20 @@ ReduceAudioLatency () {
|
||||
} else {
|
||||
auto properties = audioClient->GetProperties ();
|
||||
auto prop = properties.value();
|
||||
double currentDelay = prop.minimumBufferSize * 1000.0 / prop.sampleRate;
|
||||
double defaultDelay = prop.defaultBufferSize * 1000.0 / prop.sampleRate;
|
||||
LogMessage (LogLevel::INFO, "Audio latency: {:.2f}ms -> {:.2f}ms", defaultDelay, currentDelay);
|
||||
if (prop.minimumBufferSize < prop.defaultBufferSize) {
|
||||
double currentDelay = prop.minimumBufferSize * 1000.0 / prop.sampleRate;
|
||||
double defaultDelay = prop.defaultBufferSize * 1000.0 / prop.sampleRate;
|
||||
LogMessage (LogLevel::INFO, "Using REAL Audio latency: {:.2f}ms -> {:.2f}ms", defaultDelay, currentDelay);
|
||||
} else {
|
||||
LogMessage (LogLevel::WARN, "Using REAL Audio Failed, Please Check Audio Driver!");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init Audio patches");
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (const auto audio = openConfigSection (config_ptr.get (), "audio")) {
|
||||
real = readConfigBool (audio, "real", real);
|
||||
wasapiShared = readConfigBool (audio, "wasapi_shared", wasapiShared);
|
||||
asio = readConfigBool (audio, "asio", asio);
|
||||
asioDriver = readConfigString (audio, "asio_driver", asioDriver);
|
||||
|
||||
}
|
||||
}
|
||||
LogMessage (LogLevel::DEBUG, "Init Audio patches");
|
||||
|
||||
if (real) ReduceAudioLatency ();
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches.h"
|
||||
#include <emmintrin.h>
|
||||
#include <map>
|
||||
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
|
||||
@@ -110,7 +111,7 @@ Init () {
|
||||
fontExistAll = false;
|
||||
}
|
||||
if (fontExistAll == false) return;
|
||||
LogMessage (LogLevel::INFO, "Detected cn_xx files, Install Font patches");
|
||||
LogMessage (LogLevel::INFO, "Using Font patches (Detected cn_xx files)");
|
||||
languageData = calloc (languages.size () * languages.size () * 0x70 * 0x5, sizeof (u8));
|
||||
|
||||
switch (gameVersion) {
|
||||
@@ -388,14 +389,14 @@ Init () {
|
||||
demoMovieExistAll = false;
|
||||
}
|
||||
if (demoMovieExistAll) {
|
||||
LogMessage (LogLevel::INFO, "Detected attractdemo_cn files, install attractdemo patches!");
|
||||
LogMessage (LogLevel::INFO, "Using Attractdemo patches (Detected attractdemo_cn files)");
|
||||
INSTALL_FAST_HOOK_DYNAMIC (LoadDemoMovie, ASLR (0x1404313F0));
|
||||
}
|
||||
|
||||
bool onpCnExist = false;
|
||||
if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\textures\\onpu_cn\\onp_all.nutexb"))) onpCnExist = true;
|
||||
if (onpCnExist) {
|
||||
LogMessage (LogLevel::INFO, "Detected onpu_cn files, install onp patches!");
|
||||
LogMessage (LogLevel::INFO, "Using Onp patches (Detected onpu_cn files)");
|
||||
INSTALL_MID_HOOK_DYNAMIC (ChangeOnpFile, ASLR (0x140134D16));
|
||||
}
|
||||
language_patch.push_back (safetyhook::create_mid (ASLR (0x140134E22), [](SafetyHookContext &ctx){
|
||||
@@ -637,7 +638,7 @@ Init () {
|
||||
};
|
||||
for (std::string voiceFile : voiceFiles) checkVoiceFile (("..\\..\\Data\\x64\\sound\\" + voiceFile).c_str ());
|
||||
if (enableSwitchVoice) {
|
||||
LogMessage (LogLevel::INFO, "Detected voice files, install voice patches!");
|
||||
LogMessage (LogLevel::INFO, "Using Voice patches (Detected voice files)");
|
||||
TestMode::RegisterItemAfter(
|
||||
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']",
|
||||
L"<select-item label=\"VOICE\" param-offset-x=\"35\" replace-text=\"0:JPN, 1:CHN\" group=\"Setting\" "
|
||||
|
||||
+10
-13
@@ -2,8 +2,10 @@
|
||||
#include "helpers.h"
|
||||
#include <tomcrypt.h>
|
||||
#include <zlib.h>
|
||||
#include "config.h"
|
||||
|
||||
bool useLayeredFs = false;
|
||||
bool useLayeredFs = Config::ConfigManager::instance ().getLayeredFsConfig ().enabled;
|
||||
std::string modDir = Config::ConfigManager::instance ().getLayeredFsConfig ().mod_dir;
|
||||
|
||||
std::string datatableKey = "3530304242323633353537423431384139353134383346433246464231354534";
|
||||
std::string fumenKey = "4434423946383537303842433443383030333843444132343339373531353830";
|
||||
@@ -179,8 +181,8 @@ LayeredFsHandler (const std::string &originalFileName, const std::string ¤
|
||||
std::filesystem::path path (originalFileName.c_str ());
|
||||
if (!path.is_absolute ()) path = absolute (path);
|
||||
auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64";
|
||||
auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64";
|
||||
auto encryptedLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64_enc";
|
||||
auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / modDir / "x64";
|
||||
auto encryptedLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / modDir / "x64_enc";
|
||||
|
||||
if (path.string ().find (originalDataFolder.string ()) == 0) {
|
||||
auto newPath = path.string ();
|
||||
@@ -285,29 +287,24 @@ FAST_HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA")
|
||||
|
||||
void
|
||||
Init () {
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (const auto layeredFs = openConfigSection (config_ptr.get (), "layeredfs"))
|
||||
useLayeredFs = readConfigBool (layeredFs, "enabled", useLayeredFs);
|
||||
}
|
||||
register_cipher (&aes_desc);
|
||||
if (useLayeredFs || !beforeHandlers.empty () || !afterHandlers.empty ()) {
|
||||
LogMessage (LogLevel::INFO, "using LayeredFs! Data_mods={} beforHandlers={} afterHandlers={}",
|
||||
useLayeredFs ? "enabled" : "disabled", beforeHandlers.size (), afterHandlers.size ());
|
||||
if (!beforeHandlers.empty ()) LogMessage (LogLevel::INFO, "Using fileHandler beofre size: {}", beforeHandlers.size ());
|
||||
if (useLayeredFs) LogMessage (LogLevel::INFO, "Using LayeredFS mods folder: ", modDir);
|
||||
if (!afterHandlers.empty ()) LogMessage (LogLevel::INFO, "Using fileHandler after size: {}", afterHandlers.size ());
|
||||
INSTALL_FAST_HOOK (CreateFileAHook);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegisterBefore (const std::function<std::string (std::string, std::string)> &fileHandler) {
|
||||
LogMessage (LogLevel::DEBUG, "Registered Before");
|
||||
LogMessage (LogLevel::DEBUG, "Registered LayeredFS Before Handler");
|
||||
beforeHandlers.push_back (new RegisteredHandler (fileHandler));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterAfter (const std::function<std::string (std::string, std::string)> &fileHandler) {
|
||||
LogMessage (LogLevel::DEBUG, "Registered After");
|
||||
LogMessage (LogLevel::DEBUG, "Registered LayeredFS After Handler");
|
||||
afterHandlers.push_back (new RegisteredHandler (fileHandler));
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,6 @@ void Update ();
|
||||
void Exit ();
|
||||
// Lowlevel Card API
|
||||
void WaitTouch (CallBackTouchCard callback, uint64_t touchData);
|
||||
// Lowlevel QR API
|
||||
void InitQr (GameVersion gameVersion);
|
||||
void UsingQr ();
|
||||
void * CheckQr ();
|
||||
size_t GetQr (void *plugin, size_t size, uint8_t *buffer);
|
||||
// New API
|
||||
void InitVersion (GameVersion gameVersion);
|
||||
void InitCardReader (CommitCardCallback touch);
|
||||
|
||||
+3
-36
@@ -39,7 +39,7 @@ namespace patches::Plugins {
|
||||
if (event) ((BasicEvent)event) ();
|
||||
}
|
||||
}
|
||||
// Card API
|
||||
// Low Level Card API
|
||||
void
|
||||
WaitTouch (CallBackTouchCard callback, uint64_t touchData) {
|
||||
for (auto plugin : plugins) {
|
||||
@@ -47,35 +47,6 @@ namespace patches::Plugins {
|
||||
if (event) ((WaitTouchEvent)event) (callback, touchData);
|
||||
}
|
||||
}
|
||||
// QR API (deprecated)
|
||||
void
|
||||
InitQr (GameVersion gameVersion) {
|
||||
for (auto plugin : plugins) {
|
||||
auto event = GetProcAddress (plugin, "InitQr");
|
||||
if (event) ((SendVersionEvent)event) (gameVersion);
|
||||
}
|
||||
}
|
||||
void
|
||||
UsingQr () {
|
||||
for (auto plugin : plugins) {
|
||||
auto event = GetProcAddress (plugin, "UsingQr");
|
||||
if (event) ((BasicEvent)event) ();
|
||||
}
|
||||
}
|
||||
void *
|
||||
CheckQr () {
|
||||
for (auto plugin : plugins) {
|
||||
auto event = GetProcAddress (plugin, "UsingQr");
|
||||
if (event && ((CheckEvent)event) ()) return plugin;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
size_t
|
||||
GetQr (void *plugin, size_t size, uint8_t *buffer) {
|
||||
auto event = GetProcAddress (*(HMODULE *)plugin, "GetQr");
|
||||
if (event) return ((CopyDataEvent)event) (size, buffer);
|
||||
else return 0;
|
||||
}
|
||||
// New API
|
||||
void
|
||||
InitVersion (GameVersion gameVersion) {
|
||||
@@ -124,10 +95,10 @@ namespace patches::Plugins {
|
||||
auto name = entry.path ().wstring ();
|
||||
auto shortName = entry.path ().filename ().wstring ();
|
||||
if (HMODULE hModule = LoadLibraryW (name.c_str ()); !hModule) {
|
||||
LogMessage (LogLevel::ERROR, L"Failed to load plugin " + shortName);
|
||||
LogMessage (LogLevel::ERROR, L"Failed to load plugin: {}", shortName);
|
||||
} else {
|
||||
plugins.push_back (hModule);
|
||||
LogMessage (LogLevel::INFO, L"Loaded plugin " + shortName);
|
||||
LogMessage (LogLevel::INFO, L"Using plugin: {}", shortName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,8 +117,4 @@ namespace patches::Plugins {
|
||||
}
|
||||
}).detach ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+24
-51
@@ -12,12 +12,13 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_WINDOWS_UTF8
|
||||
#include "stb_image.h"
|
||||
#include "config.h"
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
extern std::vector<HMODULE> plugins;
|
||||
extern bool acceptInvalidCards;
|
||||
extern bool emulateCardReader;
|
||||
extern bool emulateQr;
|
||||
static bool acceptInvalidCards = Config::ConfigManager::instance ().getEmulationConfig ().accept_invalid;
|
||||
static bool emulateCardReader = Config::ConfigManager::instance ().getEmulationConfig ().card_reader;
|
||||
static bool emulateQr = Config::ConfigManager::instance ().getEmulationConfig ().qr;
|
||||
extern char accessCode1[21];
|
||||
extern char accessCode2[21];
|
||||
extern char chipId1[33];
|
||||
@@ -188,19 +189,19 @@ namespace Card {
|
||||
return 1;
|
||||
}
|
||||
|
||||
HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) {
|
||||
FAST_HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) {
|
||||
if (state != State::Disable) {
|
||||
state = State::Disable;
|
||||
patches::Plugins::UpdateStatus (StatusType::CardStatus, false);
|
||||
}
|
||||
return originalbngrw_ReqCancelOfficial (a1);
|
||||
return originalbngrw_ReqCancelOfficial.fastcall<i64> (a1);
|
||||
}
|
||||
HOOK (u64, bngrw_ReqWaitTouchOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) {
|
||||
FAST_HOOK (u64, bngrw_ReqWaitTouchOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) {
|
||||
state = State::Ready;
|
||||
patches::Plugins::UpdateStatus (StatusType::CardStatus, true);
|
||||
callbackTouch = callback;
|
||||
touchData = a5;
|
||||
return originalbngrw_ReqWaitTouchOfficial (a1, a2, a3, Internal::AgentCallbackTouchOfficial, a5);
|
||||
return originalbngrw_ReqWaitTouchOfficial.fastcall<u64> (a1, a2, a3, Internal::AgentCallbackTouchOfficial, a5);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -233,15 +234,16 @@ namespace Card {
|
||||
|
||||
void
|
||||
Init() {
|
||||
LogMessage (LogLevel::INFO, "Init Card patches");
|
||||
LogMessage (LogLevel::DEBUG, "Init Card patches");
|
||||
if (!emulateCardReader) {
|
||||
LogMessage (LogLevel::WARN, "[Card] Card reader emulation disabled!");
|
||||
INSTALL_HOOK (bngrw_ReqCancelOfficial);
|
||||
INSTALL_HOOK (bngrw_ReqWaitTouchOfficial);
|
||||
LogMessage (LogLevel::WARN, "Disable Card Reader Emulation");
|
||||
INSTALL_FAST_HOOK (bngrw_ReqCancelOfficial);
|
||||
INSTALL_FAST_HOOK (bngrw_ReqWaitTouchOfficial);
|
||||
// patches::Plugins::InitCardReader (patches::Scanner::Card::Commit);
|
||||
return;
|
||||
}
|
||||
|
||||
LogMessage (LogLevel::INFO, "Using Card Reader Emulation");
|
||||
INSTALL_FAST_HOOK (bngrw_Init)
|
||||
INSTALL_FAST_HOOK (bngrw_Fin);
|
||||
INSTALL_FAST_HOOK (bngrw_IsCmdExec);
|
||||
@@ -294,7 +296,6 @@ namespace Qr {
|
||||
FAST_HOOK_DYNAMIC (bool, Send3, i64, char) { return true; }
|
||||
FAST_HOOK_DYNAMIC (bool, Send4, i64, const void *, i64) { return true; }
|
||||
FAST_HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) {
|
||||
patches::Plugins::UsingQr ();
|
||||
lastScan = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ();
|
||||
if (state == State::CopyWait && scanQueue.size () > 0) {
|
||||
std::vector<uint8_t> *data = scanQueue.front ();
|
||||
@@ -367,41 +368,18 @@ namespace Qr {
|
||||
if ((lastScan + 200) < std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ()) {
|
||||
state = State::Disable;
|
||||
patches::Plugins::UpdateStatus (StatusType::QrStatus, false);
|
||||
} else {
|
||||
void *plugin = patches::Plugins::CheckQr ();
|
||||
if (plugin) {
|
||||
uint8_t *space = (uint8_t *)calloc (600, sizeof (uint8_t));
|
||||
size_t size = patches::Plugins::GetQr (plugin, 600, space);
|
||||
if (size > 0) {
|
||||
std::vector<uint8_t> data = {};
|
||||
for (size_t i = 0; i < size; i ++) data.push_back (space[i]);
|
||||
patches::Scanner::Qr::Commit (data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> &
|
||||
ReadQRData (std::vector<uint8_t> &buffer) {
|
||||
std::string serial = "";
|
||||
u16 type = 0;
|
||||
std::vector<i64> songNoes;
|
||||
std::string serial = Config::ConfigManager::instance ().getQrConfig ().data.serial;
|
||||
u16 type = Config::ConfigManager::instance ().getQrConfig ().data.type;
|
||||
std::vector<int> songNoes = Config::ConfigManager::instance ().getQrConfig ().data.song_no;
|
||||
|
||||
buffer.clear ();
|
||||
auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
auto qr = openConfigSection (config_ptr.get (), "qr");
|
||||
if (qr) {
|
||||
auto data = openConfigSection (qr, "data");
|
||||
if (data) {
|
||||
serial = readConfigString (data, "serial", "");
|
||||
type = (u16) readConfigInt (data, "type", 0);
|
||||
songNoes = readConfigIntArray (data, "song_no", songNoes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> header = { 0x53, 0x31, 0x32, 0x00, 0x00, 0xFF, 0xFF, (uint8_t)serial.size (), 0x01, 0x00 };
|
||||
for (uint8_t byte_data : header) buffer.push_back (byte_data);
|
||||
for (char word : serial) buffer.push_back ((uint8_t)word);
|
||||
@@ -420,18 +398,12 @@ namespace Qr {
|
||||
|
||||
std::vector<uint8_t> &
|
||||
ReadQRImage (std::vector<uint8_t> &buffer) {
|
||||
std::string imagePath = "";
|
||||
std::string imagePath = Config::ConfigManager::instance ().getQrConfig ().image_path;
|
||||
|
||||
buffer.clear ();
|
||||
auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
auto qr = openConfigSection (config_ptr.get (), "qr");
|
||||
if (qr) imagePath = readConfigString (qr, "image_path", "");
|
||||
}
|
||||
std::u8string u8PathStr (imagePath.begin (), imagePath.end ());
|
||||
std::filesystem::path u8Path (u8PathStr);
|
||||
if (!std::filesystem::is_regular_file (u8Path)) {
|
||||
if (!is_regular_file (u8Path)) {
|
||||
LogMessage (LogLevel::ERROR, "Failed to open image: {} (file not found)", u8Path.string());
|
||||
return buffer;
|
||||
}
|
||||
@@ -453,13 +425,14 @@ namespace Qr {
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init Qr patches");
|
||||
LogMessage (LogLevel::DEBUG, "Init Qr patches");
|
||||
|
||||
if (!emulateQr) {
|
||||
LogMessage (LogLevel::WARN, "[QR] QR emulation disabled!");
|
||||
LogMessage (LogLevel::WARN, "Disable QR Scanner Emulation");
|
||||
return;
|
||||
}
|
||||
patches::Plugins::InitQr (gameVersion);
|
||||
|
||||
LogMessage (LogLevel::INFO, "Using QR Scanner Emulation");
|
||||
SetConsoleOutputCP (CP_UTF8);
|
||||
auto amHandle = reinterpret_cast<u64> (GetModuleHandle ("AMFrameWork.dll"));
|
||||
switch (gameVersion) {
|
||||
@@ -528,7 +501,7 @@ Update() {
|
||||
|
||||
void
|
||||
Init() {
|
||||
LogMessage (LogLevel::INFO, "Init Scanner patches");
|
||||
LogMessage (LogLevel::DEBUG, "Init Scanner patches");
|
||||
patches::Scanner::Card::Init ();
|
||||
patches::Scanner::Qr::Init ();
|
||||
}
|
||||
|
||||
+30
-22
@@ -1,9 +1,11 @@
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches.h"
|
||||
#include "banner.h"
|
||||
#include <exception>
|
||||
#include <format>
|
||||
#include <queue>
|
||||
#include <map>
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
|
||||
@@ -20,6 +22,8 @@ std::vector<SafetyHookMid> patches = {};
|
||||
std::vector<Value *> values = {};
|
||||
std::map<std::wstring, Value *> valueMap = {};
|
||||
|
||||
std::string ver = Banner::Version::instance ().getVer ();
|
||||
|
||||
std::wstring
|
||||
mergeCondition (std::wstring original, std::wstring addition, std::wstring value) {
|
||||
size_t pos = original.find (L"/");
|
||||
@@ -57,6 +61,8 @@ public:
|
||||
if (!success) {
|
||||
LogMessage (LogLevel::ERROR, L"Failed to parse item: {}\n", this->selectItem);
|
||||
itemDoc.load_string (L"<root><text-item label=\"@Color/Red;!!!ERROR APPLYING ITEM!!!@Color/Default;\"/></root>");
|
||||
} else {
|
||||
LogMessage (LogLevel::DEBUG, L"[TestMode] Add Item: {}", itemDoc.attribute(L"label").as_string ());
|
||||
}
|
||||
// if (success) AddHookInLoop (this->registerInit);
|
||||
std::wstring layoutName = L"layout";
|
||||
@@ -90,7 +96,7 @@ public:
|
||||
size_t size = items.size ();
|
||||
if (size == 0) return node;
|
||||
size_t maxPage = size <= 14 ? 1 : (size / 13 + (size % 13 > 0));
|
||||
LogMessage (LogLevel::DEBUG, "Render testmode menu with items(size={}, page={})", size, maxPage);
|
||||
LogMessage (LogLevel::DEBUG, L"[TestMode] Add Menu {} (items={}, page={})", menuName, size, maxPage);
|
||||
std::wstring menuName = L"menu";
|
||||
pugi::xml_node parentNode = node->parent ();
|
||||
while (parentNode.name() != menuName) parentNode = parentNode.parent ();
|
||||
@@ -120,12 +126,11 @@ public:
|
||||
std::vector<pugi::xml_node> refs = {};
|
||||
|
||||
for (size_t page = 0; page < maxPage; page ++) {
|
||||
LogMessage (LogLevel::DEBUG, "Render testmode menu page ({}/{})", page + 1, maxPage);
|
||||
|
||||
// LogMessage (LogLevel::DEBUG, L"[TestMenu] menu page ({}/{})", page + 1, maxPage);
|
||||
pugi::xml_node ref = passing;
|
||||
size_t maxIndex = MIN(size - page * 13, 13);
|
||||
for (size_t index = 0; index < maxIndex; index ++) {
|
||||
LogMessage (LogLevel::DEBUG, "Render testmode menu page ({}/{}) item ({}/{})", page + 1, maxPage, index + 1, maxIndex);
|
||||
// LogMessage (LogLevel::DEBUG, "Render testmode menu page ({}/{}) item ({}/{})", page + 1, maxPage, index + 1, maxIndex);
|
||||
if (index >= refs.size ()) {
|
||||
passing = *(items[page * 13 + index]->Apply (doc, &passing));
|
||||
if (size > 14) {
|
||||
@@ -145,7 +150,7 @@ public:
|
||||
if (size == 14) passing = *(items[13]->Apply (doc, &passing));
|
||||
}
|
||||
passing = passing.parent ().last_child ();
|
||||
LogMessage (LogLevel::DEBUG, "Begin render testmode footer");
|
||||
// LogMessage (LogLevel::DEBUG, "Begin render testmode footer");
|
||||
size_t maxIndex = size == 14 ? 14 : MIN(size, 13);
|
||||
for (size_t i = 0; i < 15 - maxIndex; i++) passing = passing.parent ().insert_child_after (L"break-item", passing);
|
||||
if (maxPage > 1) {
|
||||
@@ -159,7 +164,7 @@ public:
|
||||
exit.load_string (std::format (L"<root><menu-item label=\"EXIT\" menu=\"{}\"/></root>", parentId).c_str ());
|
||||
passing = passing.parent ().insert_copy_after (exit.first_child ().first_child (), passing);
|
||||
|
||||
LogMessage (LogLevel::DEBUG, L"Insert testmode menu menuId: {}, fromId: {}", this->menuId, parentId);
|
||||
// LogMessage (LogLevel::DEBUG, L"Insert testmode menu menuId: {}, fromId: {}", this->menuId, parentId);
|
||||
pugi::xml_node root = doc->first_child ();
|
||||
root.insert_copy_after (menu.first_child ().first_child (), root.first_child ());
|
||||
return &temp;
|
||||
@@ -270,7 +275,7 @@ std::wstring
|
||||
replaceFileName (std::wstring fullFileName, std::wstring usingLastFileName) {
|
||||
size_t lastPosition = fullFileName.find_last_of (L"/");
|
||||
if (lastPosition == -1) return usingLastFileName;
|
||||
else return fullFileName.substr(0, lastPosition) + usingLastFileName;
|
||||
else return fullFileName.substr(0, lastPosition + 1) + usingLastFileName;
|
||||
}
|
||||
|
||||
FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFileName) {
|
||||
@@ -295,6 +300,7 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t
|
||||
pugi::xml_node talItem = dongleItem.parent ().append_copy (dongleItem);
|
||||
talItem.attribute (L"label").set_value (L"TAIKOARCADELOADER");
|
||||
talItem.attribute (L"id").set_value (L"TaikoArcadeLoader");
|
||||
talItem.attribute (L"replace-text").set_value ((L"1:@Color/Lime;V" + std::wstring ({ver.begin (), ver.end ()})).c_str ());
|
||||
talItem.append_attribute (L"default") = L"1";
|
||||
dongleItem.parent ().append_child (L"break-item");
|
||||
|
||||
@@ -446,7 +452,7 @@ LocalizationCHS () {
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init TestMode patches");
|
||||
LogMessage (LogLevel::DEBUG, "Init TestMode patches");
|
||||
|
||||
const u64 testModeLibrary = (u64)GetModuleHandle ("TestModeLibrary.dll");
|
||||
const u64 testModeSetMenu = testModeLibrary + 0x99D0;
|
||||
@@ -462,6 +468,7 @@ Init () {
|
||||
INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600));
|
||||
INSTALL_FAST_HOOK_DYNAMIC (SceneFirstInitialize, ASLR (0x1404574B0));
|
||||
if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) {
|
||||
LogMessage (LogLevel::INFO, L"Using DeviceInitialize: DeviceInitialize_china.xml");
|
||||
usingDeviceInitialize = L"DeviceInitialize_china.xml";
|
||||
patches.push_back (safetyhook::create_mid (ASLR (0x140465549), [](SafetyHookContext &ctx)
|
||||
{ ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x140465556); })); // DeviceCheck = Loading Font
|
||||
@@ -473,6 +480,7 @@ Init () {
|
||||
WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加载中...\0");
|
||||
}
|
||||
if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_china.xml")) {
|
||||
LogMessage (LogLevel::INFO, L"Using TestMode: TestMode_china.xml");
|
||||
usingTestMode = L"TestMode_china.xml";
|
||||
patches.push_back (safetyhook::create_mid (ASLR (0x14047C603), [](SafetyHookContext &ctx)
|
||||
{ ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x14047C610); })); // TestMode = DeviceInitialize
|
||||
@@ -524,13 +532,13 @@ SetTestModeValue (const wchar_t *itemId, int value) {
|
||||
|
||||
Menu *
|
||||
CreateMenu (const std::wstring &menuName, const std::wstring &menuId) {
|
||||
LogMessage (LogLevel::DEBUG, L"Create MenuName: {} MenuId: {}", menuName, menuId);
|
||||
// LogMessage (LogLevel::DEBUG, L"Create MenuName: {} MenuId: {}", menuName, menuId);
|
||||
return new RegisteredMenu (menuName, menuId);
|
||||
}
|
||||
|
||||
Value *
|
||||
CreateValue (const std::wstring &key) {
|
||||
LogMessage (LogLevel::DEBUG, L"Create TestMode Value key: {}", key);
|
||||
// LogMessage (LogLevel::DEBUG, L"Create TestMode Value key: {}", key);
|
||||
// if (valueMap.count (key)) return valueMap[key];
|
||||
Value *value = (Value *)(new TestModeValue (key));
|
||||
values.push_back ((Value *)value);
|
||||
@@ -540,77 +548,77 @@ CreateValue (const std::wstring &key) {
|
||||
|
||||
void
|
||||
RegisterItem (const std::wstring &item, const std::function<void ()> &initMethod, Menu *menu) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nItem: {}", item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item: {}", item);
|
||||
hooks.push_back (initMethod);
|
||||
menu->RegisterItem (new RegisteredItem (item, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItem (const std::wstring &item, const std::function<void ()> &initMethod) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nItem: {}", item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item: {}", item);
|
||||
hooks.push_back (initMethod);
|
||||
modManager->RegisterItem (new RegisteredItem (item, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItem (const std::wstring &item, Menu *menu) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nItem: {}", item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item: {}", item);
|
||||
menu->RegisterItem (new RegisteredItem (item, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItem (const std::wstring &item) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nItem: {}", item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item: {}", item);
|
||||
modManager->RegisterItem (new RegisteredItem (item, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItem (Applicable *item, Menu *menu) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register Item");
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item");
|
||||
menu->RegisterItem (item);
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItem (Applicable *item) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register Item");
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Item");
|
||||
modManager->RegisterItem (item);
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItemAfter (const std::wstring &query, const std::wstring &item, const std::function<void()> &initMethod) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nQuery: {} \nItem: {}", query, item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Query: {} Item: {}", query, item);
|
||||
hooks.push_back (initMethod);
|
||||
registeredSingleItems.push_back (new RegisteredSingleItem (query, new RegisteredItem (item, [](){})));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItemAfter (const std::wstring &query, const std::wstring &item) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nQuery: {} \nItem: {}", query, item);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Query: {} Item: {}", query, item);
|
||||
registeredSingleItems.push_back (new RegisteredSingleItem (query, new RegisteredItem (item, [](){})));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterItemAfter (const std::wstring &query, Applicable *item) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nQuery: {} \nItem: ptr", query);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Query: {} Item: ptr", query);
|
||||
registeredSingleItems.push_back (new RegisteredSingleItem (query, item));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterModify (const std::wstring &query, const std::function<void (pugi::xml_node &)> &nodeModify, const std::function<void ()> &initMethod) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nModify: {}", query);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Modify: {}", query);
|
||||
hooks.push_back (initMethod);
|
||||
registeredModifies.push_back (new RegisteredModify (query, nodeModify, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterModify (const std::wstring &query, const std::function<void (pugi::xml_node &)> &nodeModify) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register \nModify: {}", query);
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Modify: {}", query);
|
||||
registeredModifies.push_back (new RegisteredModify (query, nodeModify, [](){}));
|
||||
}
|
||||
|
||||
void
|
||||
RegisterHook (const std::function<void()> &initMethod) {
|
||||
LogMessage (LogLevel::DEBUG, L"Register Hook");
|
||||
// LogMessage (LogLevel::DEBUG, L"Register Hook");
|
||||
hooks.push_back (initMethod);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,17 +29,17 @@ namespace patches::Timer {
|
||||
NTSTATUS queryStatus = NtQueryTimerResolution(¤tResolution, &minimumResolution, &maximumResolution);
|
||||
if (queryStatus == 0) {
|
||||
bool setHighResolutionTimer = currentResolution > maximumResolution;
|
||||
LogMessage (LogLevel::WARN, "(experimental) Timer Resolution current: {}ms maximum: {}ms", currentResolution / 10000.0, maximumResolution / 10000.0);
|
||||
|
||||
if (setHighResolutionTimer) {
|
||||
NTSTATUS status = NtSetTimerResolution(maximumResolution, TRUE, ¤tResolution);
|
||||
ULONG targetResolution = currentResolution;
|
||||
NTSTATUS status = NtSetTimerResolution(maximumResolution, TRUE, &targetResolution);
|
||||
if (status == 0) {
|
||||
LogMessage (LogLevel::WARN, "(experimental) Successfully change Timer resolution to {}ms", maximumResolution / 10000.0);
|
||||
LogMessage (LogLevel::INFO, "Using HiRes Timer: {}ms -> {}ms", currentResolution / 10000.0, targetResolution / 10000.0);
|
||||
} else {
|
||||
LogMessage (LogLevel::ERROR, "(experimental) Failed to change Timer resolution, status={}", status);
|
||||
LogMessage (LogLevel::WARN, "Failed to change Timer resolution, status={}", status);
|
||||
}
|
||||
atexit (Release);
|
||||
}
|
||||
} else LogMessage (LogLevel::ERROR, "(experimental) Failed to query Timer resolution, status={}", queryStatus);
|
||||
} else LogMessage (LogLevel::WARN, "Failed to query Timer resolution, status={}", queryStatus);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "helpers.h"
|
||||
#include "../patches.h"
|
||||
#include "config.h"
|
||||
|
||||
extern std::string chassisId;
|
||||
extern i32 xRes;
|
||||
extern i32 yRes;
|
||||
extern bool vsync;
|
||||
extern bool localFiles;
|
||||
static std::string chassisId = Config::ConfigManager::instance ().getAmauthConfig ().chassis_id.value ();
|
||||
static const i32& xRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.x;
|
||||
static const i32& yRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.y;
|
||||
static bool vsync = Config::ConfigManager::instance ().getGraphicsConfig ().vsync;
|
||||
static bool localFiles = Config::ConfigManager::instance ().getPatchesConfig ().local_files;
|
||||
|
||||
namespace patches::CHN00 {
|
||||
int language = 0;
|
||||
@@ -105,11 +106,11 @@ ReplaceLeaBufferAddress (const std::vector<uintptr_t> &bufferAddresses, void *ne
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init CHN00 patches");
|
||||
bool unlockSongs = true;
|
||||
bool fixLanguage = false;
|
||||
bool demoMovie = true;
|
||||
bool modeCollabo025 = false;
|
||||
bool modeCollabo026 = false;
|
||||
bool unlockSongs = Config::ConfigManager::instance ().getPatchesConfig ().unlock_songs;
|
||||
bool fixLanguage = Config::ConfigManager::instance ().getPatchesConfig ().chn00.fix_language;
|
||||
bool demoMovie = Config::ConfigManager::instance ().getPatchesConfig ().chn00.demo_movie;
|
||||
bool modeCollabo025 = Config::ConfigManager::instance ().getPatchesConfig ().chn00.mode_collabo025;
|
||||
bool modeCollabo026 = Config::ConfigManager::instance ().getPatchesConfig ().chn00.mode_collabo026;
|
||||
|
||||
haspBuffer = static_cast<u8 *> (malloc (0xD40));
|
||||
memset (haspBuffer, 0, 0xD40);
|
||||
@@ -128,20 +129,6 @@ Init () {
|
||||
INSTALL_HOOK (HaspGetInfo);
|
||||
INSTALL_HOOK (HaspRead);
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (const auto patches = openConfigSection (config_ptr.get (), "patches")) {
|
||||
unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs);
|
||||
if (const auto chn00 = openConfigSection (patches, "chn00")) {
|
||||
fixLanguage = readConfigBool (chn00, "fix_language", fixLanguage);
|
||||
demoMovie = readConfigBool (chn00, "demo_movie", demoMovie);
|
||||
modeCollabo025 = readConfigBool (chn00, "mode_collabo025", modeCollabo025);
|
||||
modeCollabo026 = readConfigBool (chn00, "mode_collabo026", modeCollabo026);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply common config patch
|
||||
WRITE_MEMORY (ASLR (0x1404A4ED3), i32, xRes);
|
||||
WRITE_MEMORY (ASLR (0x1404A4EDA), i32, yRes);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "helpers.h"
|
||||
#include "../patches.h"
|
||||
#include "config.h"
|
||||
|
||||
extern i32 xRes;
|
||||
extern i32 yRes;
|
||||
extern bool vsync;
|
||||
extern bool localFiles;
|
||||
|
||||
static const i32& xRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.x;
|
||||
static const i32& yRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.y;
|
||||
static bool vsync = Config::ConfigManager::instance ().getGraphicsConfig ().vsync;
|
||||
static bool localFiles = Config::ConfigManager::instance ().getPatchesConfig ().local_files;
|
||||
namespace patches::JPN00 {
|
||||
|
||||
HOOK_DYNAMIC (char, AMFWTerminate, i64) { return 0; }
|
||||
@@ -42,14 +42,7 @@ ReplaceLeaBufferAddress (const std::vector<uintptr_t> &bufferAddresses, void *ne
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init JNP00 patches");
|
||||
bool unlockSongs = true;
|
||||
|
||||
const auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (const auto patches = openConfigSection (config_ptr.get (), "patches"))
|
||||
unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs);
|
||||
}
|
||||
bool unlockSongs = Config::ConfigManager::instance ().getPatchesConfig ().unlock_songs;
|
||||
|
||||
// Apply common config patch
|
||||
WRITE_MEMORY (ASLR (0x140224B2B), i32, xRes);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "helpers.h"
|
||||
#include "../patches.h"
|
||||
#include "config.h"
|
||||
|
||||
extern u64 song_data_size;
|
||||
extern void *song_data;
|
||||
extern i32 xRes;
|
||||
extern i32 yRes;
|
||||
extern bool vsync;
|
||||
extern bool localFiles;
|
||||
|
||||
static const i32& xRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.x;
|
||||
static const i32& yRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.y;
|
||||
static bool vsync = Config::ConfigManager::instance ().getGraphicsConfig ().vsync;
|
||||
static bool localFiles = Config::ConfigManager::instance ().getPatchesConfig ().local_files;
|
||||
#define RDX_MOV 0x48, 0xBA
|
||||
#define R8_MOV 0x49, 0xB8
|
||||
#define GENERATE_MOV(instruction, location) \
|
||||
@@ -52,13 +52,7 @@ ReplaceLeaBufferAddress (const std::vector<uintptr_t> &bufferAddresses, void *ne
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init JPN08 patches");
|
||||
bool unlockSongs = true;
|
||||
|
||||
auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (auto patches = openConfigSection (config_ptr.get (), "patches")) unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs);
|
||||
}
|
||||
bool unlockSongs = Config::ConfigManager::instance ().getPatchesConfig ().unlock_songs;
|
||||
|
||||
// Apply common config patch
|
||||
WRITE_MEMORY (ASLR (0x14035FC5B), i32, xRes);
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
#include "helpers.h"
|
||||
#include "../patches.h"
|
||||
#include <map>
|
||||
#include "config.h"
|
||||
|
||||
extern i32 xRes;
|
||||
extern i32 yRes;
|
||||
extern bool vsync;
|
||||
extern bool localFiles;
|
||||
static const i32& xRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.x;
|
||||
static const i32& yRes = Config::ConfigManager::instance ().getGraphicsConfig ().res.y;
|
||||
static bool vsync = Config::ConfigManager::instance ().getGraphicsConfig ().vsync;
|
||||
static bool localFiles = Config::ConfigManager::instance ().getPatchesConfig ().local_files;
|
||||
|
||||
namespace patches::JPN39 {
|
||||
int language = 0;
|
||||
@@ -313,8 +314,8 @@ uint8_t *datatableBuffer[3] = { nullptr };
|
||||
std::vector<SafetyHookMid> datatable_patch = {};
|
||||
#define DATATABLE_PATCH_REGISTER(location, reg, value, skip) { datatable_patch.push_back(safetyhook::create_mid(location, [](SafetyHookContext &ctx) {ctx.reg = (uintptr_t)(value); ctx.rip = location + skip;})); }
|
||||
void
|
||||
ReplaceDatatableBufferAddresses () {
|
||||
LogMessage (LogLevel::INFO, "Set Datatable Size to 12MB");
|
||||
PatchDatatable () {
|
||||
LogMessage (LogLevel::INFO, "Using Datatable patch size: 12MB");
|
||||
for (int i = 0; i < 3; i ++) datatableBuffer[i] = (uint8_t *)malloc (datatableBufferSize);
|
||||
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE26), r8, datatableBufferSize, 6);
|
||||
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE3A), r8, datatableBufferSize, 6);
|
||||
@@ -333,20 +334,9 @@ ReplaceDatatableBufferAddresses () {
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init JPN39 patches");
|
||||
bool unlockSongs = true;
|
||||
double modelResRate = 1.0;
|
||||
|
||||
auto configPath = std::filesystem::current_path () / "config.toml";
|
||||
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (auto patches = openConfigSection (config_ptr.get (), "patches")) {
|
||||
unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs);
|
||||
}
|
||||
if (auto graphics = openConfigSection (config_ptr.get (), "graphics")) {
|
||||
modelResRate = readConfigDouble (graphics, "model_res_rate", modelResRate);
|
||||
}
|
||||
}
|
||||
LogMessage (LogLevel::DEBUG, "Init JPN39 patches");
|
||||
bool unlockSongs = Config::ConfigManager::instance ().getPatchesConfig ().unlock_songs;
|
||||
double modelResRate = Config::ConfigManager::instance ().getGraphicsConfig ().model_res_rate;
|
||||
|
||||
// Hook to get AppAccessor and ComponentAccessor
|
||||
INSTALL_FAST_HOOK (DeviceCheck);
|
||||
@@ -360,7 +350,7 @@ Init () {
|
||||
if (modelResRate > 0) {
|
||||
i32 donModelX = (i32)(xRes * modelResRate);
|
||||
i32 donModelY = (i32)(yRes * modelResRate);
|
||||
LogMessage (LogLevel::INFO, "Patch DonModel use resolution {}x{}", donModelX, donModelY);
|
||||
LogMessage (LogLevel::INFO, "Using DonModel Resolutin: {}x{}", donModelX, donModelY);
|
||||
WRITE_MEMORY (ASLR (0x1404F3D5B), i32, donModelX);
|
||||
WRITE_MEMORY (ASLR (0x1404F3D62), i32, donModelY);
|
||||
}
|
||||
@@ -374,7 +364,7 @@ Init () {
|
||||
WRITE_MEMORY (ASLR (0x140580459), u8, 0x10);
|
||||
|
||||
// Remove datatable size limit
|
||||
ReplaceDatatableBufferAddresses ();
|
||||
PatchDatatable ();
|
||||
|
||||
// Unlock Songs
|
||||
TestMode::RegisterItem (
|
||||
|
||||
+21
-11
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <SDL3/SDL.h>
|
||||
#include <array>
|
||||
#include "helpers.h"
|
||||
#include "bnusio.h"
|
||||
|
||||
@@ -9,8 +10,8 @@
|
||||
|
||||
// #define ASYNC_IO
|
||||
|
||||
enum SDLAxis {
|
||||
SDL_AXIS_NULL,
|
||||
enum class SDLAxis {
|
||||
SDL_AXIS_NULL = 0,
|
||||
SDL_AXIS_LEFT_LEFT,
|
||||
SDL_AXIS_LEFT_RIGHT,
|
||||
SDL_AXIS_LEFT_UP,
|
||||
@@ -37,16 +38,16 @@ struct SDLAxisState {
|
||||
float RTriggerDown;
|
||||
};
|
||||
|
||||
enum Scroll { MOUSE_SCROLL_INVALID, MOUSE_SCROLL_UP, MOUSE_SCROLL_DOWN };
|
||||
enum class Scroll { MOUSE_SCROLL_INVALID = 0, MOUSE_SCROLL_UP, MOUSE_SCROLL_DOWN };
|
||||
|
||||
struct Keybindings {
|
||||
u8 keycodes[255] = { '\0' };
|
||||
SDL_GamepadButton buttons[255] = { SDL_GAMEPAD_BUTTON_INVALID };
|
||||
SDLAxis axis[255] = { SDL_AXIS_NULL };
|
||||
Scroll scroll[2] = { MOUSE_SCROLL_INVALID };
|
||||
std::array<u8, 255> keycodes = { };
|
||||
std::array<SDL_GamepadButton, 255> buttons = { SDL_GAMEPAD_BUTTON_INVALID };
|
||||
std::array<SDLAxis, 255> axis = {SDLAxis::SDL_AXIS_NULL };
|
||||
std::array<Scroll,2> scroll = {Scroll::MOUSE_SCROLL_INVALID };
|
||||
};
|
||||
|
||||
enum EnumType { none, keycode, button, axis, scroll };
|
||||
enum class EnumType { none, keycode, button, axis, scroll };
|
||||
|
||||
struct ConfigValue {
|
||||
EnumType type;
|
||||
@@ -64,11 +65,20 @@ struct InternalButtonState {
|
||||
bool Tapped;
|
||||
};
|
||||
|
||||
struct KeyCodePair {
|
||||
std::string string;
|
||||
u8 keycode;
|
||||
};
|
||||
|
||||
struct MouseState {
|
||||
POINT Position;
|
||||
POINT RelativePosition;
|
||||
bool ScrolledUp;
|
||||
bool ScrolledDown;
|
||||
} inline currentMouseState, lastMouseState;
|
||||
|
||||
bool InitializePoll (HWND windowHandle);
|
||||
void DisposePoll ();
|
||||
void SetKeyboardButtons ();
|
||||
ConfigValue StringToConfigEnum (const char *value);
|
||||
void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind, u8 *inputState);
|
||||
InternalButtonState GetInternalButtonState (const Keybindings &bindings);
|
||||
void SetRumble (int left, int right, int length);
|
||||
|
||||
|
||||
+73
-174
@@ -1,19 +1,19 @@
|
||||
#include "poll.h"
|
||||
|
||||
#ifdef ASYNC_IO
|
||||
#include "polldef.h"
|
||||
#define SDL_MAIN_NOIMPL
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
extern bool jpLayout;
|
||||
extern int exited;
|
||||
extern u8 inputState;
|
||||
#include "config.h"
|
||||
|
||||
static bool jpLayout = Config::ConfigManager::instance ().getKeyboardConfig ().jp_layout;
|
||||
static bool autoIme = Config::ConfigManager::instance ().getKeyboardConfig ().auto_ime;
|
||||
static bool globalKeyboard = Config::ConfigManager::instance ().getControllerConfig ().global_keyboard;
|
||||
static bool simpleInput = Config::ConfigManager::instance ().getControllerConfig ().simple_input;
|
||||
static bool emulateUsio = Config::ConfigManager::instance ().getEmulationConfig ().usio;
|
||||
|
||||
extern float axisThreshold;
|
||||
extern bool globalKeyboardInput;
|
||||
extern bool autoIme;
|
||||
extern HKL currentLayout;
|
||||
extern bool emulateUsio;
|
||||
extern bool globalKeyboard;
|
||||
|
||||
bool wndForeground = false;
|
||||
bool usingKeyboard = false;
|
||||
@@ -32,11 +32,11 @@ char currentMouseWheelDirection = 0;
|
||||
uint8_t mouseWheelCount[2] = { 0 };
|
||||
uint8_t mouseWheelDiff[2] = { 0 };
|
||||
// SDLAxisState currentControllerAxisState;
|
||||
float currentControllerAxisState[SDL_AXIS_MAX] = { 0.0 };
|
||||
uint8_t controllerAxisCount[SDL_AXIS_MAX] = { 0 };
|
||||
uint8_t controllerAxisDiff[SDL_AXIS_MAX] = { 0 };
|
||||
float currentControllerAxisState[static_cast<size_t>(SDLAxis::SDL_AXIS_MAX)] = { 0.0 };
|
||||
uint8_t controllerAxisCount[static_cast<size_t>(SDLAxis::SDL_AXIS_MAX)] = { 0 };
|
||||
uint8_t controllerAxisDiff[static_cast<size_t>(SDLAxis::SDL_AXIS_MAX)] = { 0 };
|
||||
|
||||
int maxCount = 1;
|
||||
int maxCount = 10;
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Gamepad *controllers[255];
|
||||
@@ -44,81 +44,6 @@ bool flipped[255];
|
||||
|
||||
std::thread updatePollThread;
|
||||
|
||||
void
|
||||
SetKeyboardButtons () {
|
||||
ConfigKeyboardButtonsCount = jpLayout ? std::size (ConfigKeyboardButtons_JP) : std::size (ConfigKeyboardButtons_US);
|
||||
ConfigKeyboardButtons = static_cast<KeyCodePair *> (malloc (ConfigKeyboardButtonsCount * sizeof (KeyCodePair)));
|
||||
memcpy (ConfigKeyboardButtons, jpLayout ? ConfigKeyboardButtons_JP : ConfigKeyboardButtons_US, ConfigKeyboardButtonsCount * sizeof (KeyCodePair));
|
||||
}
|
||||
|
||||
void
|
||||
SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind, u8 *inputState) {
|
||||
const toml_array_t *array = toml_array_in (table, key);
|
||||
if (!array) {
|
||||
LogMessage (LogLevel::WARN, std::string (key) + ": Cannot find array");
|
||||
return;
|
||||
}
|
||||
|
||||
memset (key_bind, 0, sizeof (*key_bind));
|
||||
for (size_t i = 0; i < std::size (key_bind->buttons); i++)
|
||||
key_bind->buttons[i] = SDL_GAMEPAD_BUTTON_INVALID;
|
||||
|
||||
for (int idx = 0;; idx++) {
|
||||
const auto [ok, u] = toml_string_at (array, idx);
|
||||
if (!ok) break;
|
||||
const ConfigValue value = StringToConfigEnum (u.s);
|
||||
free (u.s);
|
||||
|
||||
switch (value.type) {
|
||||
case keycode: {
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=keycode value={}", key, (int)value.keycode);
|
||||
*inputState |= 1;
|
||||
for (int i = 0; i < std::size (key_bind->keycodes); i++) {
|
||||
if (key_bind->keycodes[i] == 0) {
|
||||
key_bind->keycodes[i] = value.keycode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case button: {
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=button value={}", key, (int)value.button);
|
||||
*inputState |= (1 << 2);
|
||||
for (int i = 0; i < std::size (key_bind->buttons); i++) {
|
||||
if (key_bind->buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
key_bind->buttons[i] = value.button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case axis: {
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=axis value={}", key, (int)value.axis);
|
||||
*inputState |= (1 << 2);
|
||||
for (int i = 0; i < std::size (key_bind->axis); i++) {
|
||||
if (key_bind->axis[i] == 0) {
|
||||
key_bind->axis[i] = value.axis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case scroll: {
|
||||
LogMessage (LogLevel::DEBUG, "config {} type=scroll value={}", key, (int)value.scroll);
|
||||
*inputState |= (1 << 1);
|
||||
for (int i = 0; i < std::size (key_bind->scroll); i++) {
|
||||
if (key_bind->scroll[i] == 0) {
|
||||
key_bind->scroll[i] = value.scroll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 钩子句柄
|
||||
HHOOK keyboardHook;
|
||||
HHOOK mouseHook;
|
||||
@@ -177,10 +102,10 @@ void KeyboardMainLoop() {
|
||||
if (usingKeyboard) {
|
||||
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0);
|
||||
if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n");
|
||||
else LogMessage (LogLevel::INFO, "KeyboardLL hook installed!");
|
||||
else LogMessage (LogLevel::DEBUG, "KeyboardLL hook installed!");
|
||||
}
|
||||
if (maxCount > 2) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount);
|
||||
LogMessage (LogLevel::WARN, "(experimental) Using Async IO!");
|
||||
if (maxCount > 2) LogMessage (LogLevel::WARN, "Using Cache count max={}", maxCount);
|
||||
LogMessage (LogLevel::INFO, "Using Async Keyboard");
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, hwnd, 0, 0) > 0) {
|
||||
TranslateMessage(&msg);
|
||||
@@ -191,9 +116,7 @@ void KeyboardMainLoop() {
|
||||
|
||||
void
|
||||
InitializeKeyboard () {
|
||||
if (usingKeyboard) {
|
||||
std::thread (KeyboardMainLoop).detach ();
|
||||
}
|
||||
std::thread (KeyboardMainLoop).detach ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -208,13 +131,15 @@ InitializePoll (HWND windowHandle) {
|
||||
wndForeground = windowHandle == GetForegroundWindow ();
|
||||
if (!emulateUsio) return false;
|
||||
|
||||
usingKeyboard = inputState & 1;
|
||||
usingMouse = inputState & (1 << 1);
|
||||
usingController = inputState & (1 << 2);
|
||||
usingKeyboard = Config::ConfigManager::instance ().getKeyBindings ().usingKeyboard();
|
||||
usingMouse = Config::ConfigManager::instance ().getKeyBindings ().usingMouse();
|
||||
usingController = Config::ConfigManager::instance ().getKeyBindings ().usingController();
|
||||
usingSDLEvent = usingMouse || usingController;
|
||||
|
||||
if (simpleInput) LogMessage (LogLevel::INFO, "Using Simple Input (1-1 bind)");
|
||||
|
||||
atexit ([](){ if (currentLayout != nullptr) ActivateKeyboardLayout (currentLayout, KLF_SETFORPROCESS);});
|
||||
InitializeKeyboard ();
|
||||
if (usingKeyboard) InitializeKeyboard ();
|
||||
if (usingSDLEvent) {
|
||||
LogMessage (LogLevel::DEBUG, "InitializePoll");
|
||||
bool hasRumble = true;
|
||||
@@ -324,9 +249,9 @@ CleanPoll () {
|
||||
|
||||
if (usingController) {
|
||||
for (int i=0; i<SDL_GAMEPAD_BUTTON_COUNT; i++) controllerCount[i] -= (bool)controllerDiff[i];
|
||||
for (int i=1; i<SDL_AXIS_MAX; i++) controllerAxisCount[i] -= (bool)controllerAxisDiff[i];
|
||||
for (int i=1; i< static_cast<int>(SDLAxis::SDL_AXIS_MAX); i++) controllerAxisCount[i] -= (bool)controllerAxisDiff[i];
|
||||
memset (controllerDiff, 0, SDL_GAMEPAD_BUTTON_COUNT);
|
||||
memset (controllerAxisDiff, 0, SDL_AXIS_MAX);
|
||||
memset (controllerAxisDiff, 0, static_cast<size_t>(SDLAxis::SDL_AXIS_MAX));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +259,7 @@ void
|
||||
UpdatePoll (HWND windowHandle) {
|
||||
if (!CheckForegroundWindow (windowHandle)) return;
|
||||
if (!emulateUsio) return;
|
||||
CleanPoll ();
|
||||
if (!simpleInput) CleanPoll ();
|
||||
if (usingSDLEvent) {
|
||||
SDL_Event event;
|
||||
SDL_Gamepad *controller;
|
||||
@@ -413,38 +338,6 @@ DisposePoll () {
|
||||
SDL_Quit ();
|
||||
}
|
||||
|
||||
ConfigValue
|
||||
StringToConfigEnum (const char *value) {
|
||||
ConfigValue rval = {};
|
||||
for (size_t i = 0; i < ConfigKeyboardButtonsCount; ++i)
|
||||
if (!strcmp (value, ConfigKeyboardButtons[i].string)) {
|
||||
rval.type = keycode;
|
||||
rval.keycode = ConfigKeyboardButtons[i].keycode;
|
||||
return rval;
|
||||
}
|
||||
for (const auto &[string, button_] : ConfigControllerButtons)
|
||||
if (!strcmp (value, string)) {
|
||||
rval.type = button;
|
||||
rval.button = button_;
|
||||
return rval;
|
||||
}
|
||||
for (const auto &[string, axis_] : ConfigControllerAXIS)
|
||||
if (!strcmp (value, string)) {
|
||||
rval.type = axis;
|
||||
rval.axis = axis_;
|
||||
return rval;
|
||||
}
|
||||
for (auto &[string, scroll_] : ConfigMouseScroll)
|
||||
if (!strcmp (value, string)) {
|
||||
rval.type = scroll;
|
||||
rval.scroll = scroll_;
|
||||
return rval;
|
||||
}
|
||||
|
||||
LogMessage (LogLevel::ERROR, std::string (value) + ": Unknown value");
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
SetRumble (int left, int right, int length) {
|
||||
for (auto &controller : controllers) {
|
||||
@@ -464,8 +357,11 @@ int maxKeyboardCount = 1;
|
||||
bool
|
||||
KeyboardIsTapped (const uint8_t keycode) {
|
||||
if (keyboardCount[keycode] > 0) {
|
||||
keyboardDiff[keycode] = 1;
|
||||
keyboardClean = true;
|
||||
if (simpleInput) keyboardCount[keycode] --;
|
||||
else {
|
||||
keyboardDiff[keycode] = 1;
|
||||
keyboardClean = true;
|
||||
}
|
||||
return true;
|
||||
} return false;
|
||||
}
|
||||
@@ -482,16 +378,17 @@ GetMouseScrollDown () {
|
||||
|
||||
bool
|
||||
GetMouseScrollIsDown (const Scroll scroll) {
|
||||
if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp ();
|
||||
if (scroll == Scroll::MOUSE_SCROLL_UP) return GetMouseScrollUp ();
|
||||
else return GetMouseScrollDown ();
|
||||
}
|
||||
|
||||
int maxWheelCount = 1;
|
||||
bool
|
||||
GetMouseScrollIsTapped (const Scroll scroll) {
|
||||
if (scroll == MOUSE_SCROLL_INVALID) return false;
|
||||
if (mouseWheelCount[scroll - 1] > 0) {
|
||||
mouseWheelDiff[scroll - 1] = 1;
|
||||
if (scroll == Scroll::MOUSE_SCROLL_INVALID) return false;
|
||||
if (mouseWheelCount[(int)scroll - 1] > 0) {
|
||||
if (simpleInput) mouseWheelCount[(int)scroll - 1] --;
|
||||
else mouseWheelDiff[(int)scroll - 1] = 1;
|
||||
return true;
|
||||
} return false;
|
||||
}
|
||||
@@ -505,71 +402,73 @@ int maxButtonCount = 1;
|
||||
bool
|
||||
ControllerButtonIsTapped (const SDL_GamepadButton button) {
|
||||
if (controllerCount[button] > 0) {
|
||||
controllerDiff[button] = 1;
|
||||
if (simpleInput) controllerCount[button] --;
|
||||
else controllerDiff[button] = 1;
|
||||
return true;
|
||||
} return false;
|
||||
}
|
||||
|
||||
float
|
||||
ControllerAxisIsDown (const SDLAxis axis) {
|
||||
return currentControllerAxisState[axis];
|
||||
return currentControllerAxisState[(int)axis];
|
||||
}
|
||||
|
||||
bool
|
||||
ControllerAxisIsTapped (const SDLAxis axis) {
|
||||
if (controllerAxisCount[axis] > 0) {
|
||||
controllerAxisDiff[axis] = 1;
|
||||
if (controllerAxisCount[(int)axis] > 0) {
|
||||
if (simpleInput) controllerAxisCount[(int)axis] --;
|
||||
else controllerAxisDiff[(int)axis] = 1;
|
||||
return true;
|
||||
} return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IsButtonTapped (const Keybindings &bindings) {
|
||||
for (size_t i = 0; i < ConfigKeyboardButtonsCount; i++) {
|
||||
if (bindings.keycodes[i] == '\0') continue;
|
||||
if (KeyboardIsTapped (bindings.keycodes[i])) {
|
||||
return true;
|
||||
}
|
||||
for (const auto keycode : bindings.keycodes) {
|
||||
if (keycode == 0) continue;
|
||||
if (KeyboardIsTapped (keycode)) return true;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) {
|
||||
if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue;
|
||||
if (ControllerButtonIsTapped (bindings.buttons[i])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto button : bindings.buttons) {
|
||||
if (button == SDL_GAMEPAD_BUTTON_INVALID) continue;
|
||||
if (ControllerButtonIsTapped (button)) return true;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) {
|
||||
if (bindings.axis[i] == SDL_AXIS_NULL) continue;
|
||||
if (ControllerAxisIsTapped (bindings.axis[i])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto axis : bindings.axis) {
|
||||
if (axis == SDLAxis::SDL_AXIS_NULL) continue;
|
||||
if (ControllerAxisIsTapped (axis)) return true;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigMouseScroll); i++) {
|
||||
if (bindings.scroll[i] == MOUSE_SCROLL_INVALID) continue;
|
||||
if (GetMouseScrollIsTapped (bindings.scroll[i])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto scroll : bindings.scroll) {
|
||||
if (scroll == Scroll::MOUSE_SCROLL_INVALID) continue;
|
||||
if (GetMouseScrollIsTapped (scroll)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float
|
||||
IsButtonDown (const Keybindings &bindings) {
|
||||
for (size_t i = 0; i < ConfigKeyboardButtonsCount; i++) {
|
||||
if (bindings.keycodes[i] == 0) continue;
|
||||
if (KeyboardIsDown (bindings.keycodes[i])) return 1.0f;
|
||||
for (const auto keycode : bindings.keycodes) {
|
||||
if (keycode == 0) continue;
|
||||
if (KeyboardIsDown (keycode)) return 1.0f;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) {
|
||||
if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue;
|
||||
if (ControllerButtonIsDown (bindings.buttons[i])) return 1.0f;
|
||||
|
||||
for (const auto button : bindings.buttons) {
|
||||
if (button == SDL_GAMEPAD_BUTTON_INVALID) continue;
|
||||
if (ControllerButtonIsDown (button)) return 1.0f;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) {
|
||||
if (bindings.axis[i] == 0) continue;
|
||||
if (float val = ControllerAxisIsDown (bindings.axis[i]); val > 0) return val;
|
||||
|
||||
for (const auto axis : bindings.axis) {
|
||||
if (axis == SDLAxis::SDL_AXIS_NULL) continue;
|
||||
if (float val = ControllerAxisIsDown (axis); val > 0) return val;
|
||||
}
|
||||
for (size_t i = 0; i < std::size (ConfigMouseScroll); i++) {
|
||||
if (bindings.scroll[i] == 0) continue;
|
||||
if (GetMouseScrollIsDown (bindings.scroll[i])) return 1.0f;
|
||||
|
||||
for (const auto scroll : bindings.scroll) {
|
||||
if (scroll == Scroll::MOUSE_SCROLL_INVALID) continue;
|
||||
if (GetMouseScrollIsDown (scroll)) return 1.0f;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
#endif
|
||||
-306
@@ -1,306 +0,0 @@
|
||||
#pragma once
|
||||
#include "poll.h"
|
||||
|
||||
struct KeyCodePair {
|
||||
const char *string;
|
||||
u8 keycode;
|
||||
};
|
||||
size_t ConfigKeyboardButtonsCount = 0;
|
||||
KeyCodePair *ConfigKeyboardButtons = nullptr;
|
||||
KeyCodePair ConfigKeyboardButtons_US[] = {
|
||||
// Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Row 1
|
||||
{"ESCAPE", VK_ESCAPE},
|
||||
{"F1", VK_F1},
|
||||
{"F2", VK_F2},
|
||||
{"F3", VK_F3},
|
||||
{"F4", VK_F4},
|
||||
{"F5", VK_F5},
|
||||
{"F6", VK_F6},
|
||||
{"F7", VK_F7},
|
||||
{"F8", VK_F8},
|
||||
{"F9", VK_F9},
|
||||
{"F10", VK_F10},
|
||||
{"F11", VK_F11},
|
||||
{"F12", VK_F12},
|
||||
|
||||
// Row 2
|
||||
{"`", VK_OEM_3},
|
||||
{"1", '1'},
|
||||
{"2", '2'},
|
||||
{"3", '3'},
|
||||
{"4", '4'},
|
||||
{"5", '5'},
|
||||
{"6", '6'},
|
||||
{"7", '7'},
|
||||
{"8", '8'},
|
||||
{"9", '9'},
|
||||
{"0", '0'},
|
||||
{"-", VK_OEM_MINUS},
|
||||
{"=", VK_OEM_PLUS},
|
||||
{"BACKSPACE", VK_BACK},
|
||||
|
||||
// Row 3
|
||||
{"TAB", VK_TAB},
|
||||
{"Q", 'Q'},
|
||||
{"W", 'W'},
|
||||
{"E", 'E'},
|
||||
{"R", 'R'},
|
||||
{"T", 'T'},
|
||||
{"Y", 'Y'},
|
||||
{"U", 'U'},
|
||||
{"I", 'I'},
|
||||
{"O", 'O'},
|
||||
{"P", 'P'},
|
||||
{"[", VK_OEM_4},
|
||||
{"]", VK_OEM_6},
|
||||
{"BACKSLASH", VK_OEM_5},
|
||||
|
||||
// Row 4
|
||||
{"CAPS_LOCK", VK_CAPITAL},
|
||||
{"A", 'A'},
|
||||
{"S", 'S'},
|
||||
{"D", 'D'},
|
||||
{"F", 'F'},
|
||||
{"G", 'G'},
|
||||
{"H", 'H'},
|
||||
{"J", 'J'},
|
||||
{"K", 'K'},
|
||||
{"L", 'L'},
|
||||
{";", VK_OEM_1},
|
||||
{"'", VK_OEM_7},
|
||||
{"ENTER", VK_RETURN},
|
||||
|
||||
// Row 5
|
||||
{"SHIFT", VK_SHIFT},
|
||||
{"Z", 'Z'},
|
||||
{"X", 'X'},
|
||||
{"C", 'C'},
|
||||
{"V", 'V'},
|
||||
{"B", 'B'},
|
||||
{"N", 'N'},
|
||||
{"M", 'M'},
|
||||
{",", VK_OEM_COMMA},
|
||||
{".", VK_OEM_PERIOD},
|
||||
{"SLASH", VK_OEM_2},
|
||||
|
||||
// Row 6
|
||||
{"CONTROL", VK_CONTROL},
|
||||
{"L_WIN", VK_LWIN},
|
||||
{"ALT", VK_MENU},
|
||||
{"SPACE", VK_SPACE},
|
||||
{"R_WIN", VK_RWIN},
|
||||
{"MENU", VK_APPS},
|
||||
|
||||
// Other Keys
|
||||
// PrtSc is more important when making snapshots, therefore comment it as reserved
|
||||
//{"PRINT_SCREEN", VK_SNAPSHOT},
|
||||
{"SCROLL_LOCK", VK_SCROLL},
|
||||
{"PAUSE", VK_PAUSE},
|
||||
{"INSERT", VK_INSERT},
|
||||
{"DELETE", VK_DELETE},
|
||||
{"HOME", VK_HOME},
|
||||
{"END", VK_END},
|
||||
{"PAGE_UP", VK_PRIOR},
|
||||
{"PAGE_DOWN", VK_NEXT},
|
||||
|
||||
// Arrow Keys
|
||||
{"UPARROW", VK_UP},
|
||||
{"LEFTARROW", VK_LEFT},
|
||||
{"DOWNARROW", VK_DOWN},
|
||||
{"RIGHTARROW", VK_RIGHT},
|
||||
|
||||
// NUMPAD Keys
|
||||
{"NUM_LOCK", VK_NUMLOCK},
|
||||
{"DIVIDE", VK_DIVIDE},
|
||||
{"MULTIPLY", VK_MULTIPLY},
|
||||
{"SUBTRACT", VK_SUBTRACT},
|
||||
{"NUM7", VK_NUMPAD7},
|
||||
{"NUM8", VK_NUMPAD8},
|
||||
{"NUM9", VK_NUMPAD9},
|
||||
{"ADD", VK_ADD},
|
||||
{"NUM4", VK_NUMPAD4},
|
||||
{"NUM5", VK_NUMPAD5},
|
||||
{"NUM6", VK_NUMPAD6},
|
||||
{"NUM1", VK_NUMPAD1},
|
||||
{"NUM2", VK_NUMPAD2},
|
||||
{"NUM3", VK_NUMPAD3},
|
||||
{"NUM0", VK_NUMPAD0},
|
||||
{"DECIMAL", VK_DECIMAL},
|
||||
};
|
||||
KeyCodePair ConfigKeyboardButtons_JP[] = {
|
||||
// Reference:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Wayback Machine:https://web.archive.org/web/20231223135232/https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
||||
// Row 1
|
||||
{"ESCAPE", VK_ESCAPE},
|
||||
{"F1", VK_F1},
|
||||
{"F2", VK_F2},
|
||||
{"F3", VK_F3},
|
||||
{"F4", VK_F4},
|
||||
{"F5", VK_F5},
|
||||
{"F6", VK_F6},
|
||||
{"F7", VK_F7},
|
||||
{"F8", VK_F8},
|
||||
{"F9", VK_F9},
|
||||
{"F10", VK_F10},
|
||||
{"F11", VK_F11},
|
||||
{"F12", VK_F12},
|
||||
|
||||
// Row 2
|
||||
{"1", '1'},
|
||||
{"2", '2'},
|
||||
{"3", '3'},
|
||||
{"4", '4'},
|
||||
{"5", '5'},
|
||||
{"6", '6'},
|
||||
{"7", '7'},
|
||||
{"8", '8'},
|
||||
{"9", '9'},
|
||||
{"0", '0'},
|
||||
{"-", VK_OEM_MINUS},
|
||||
{"^", VK_OEM_7},
|
||||
{"YEN", VK_OEM_5},
|
||||
{"BACKSPACE", VK_BACK},
|
||||
|
||||
// Row 3
|
||||
{"TAB", VK_TAB},
|
||||
{"Q", 'Q'},
|
||||
{"W", 'W'},
|
||||
{"E", 'E'},
|
||||
{"R", 'R'},
|
||||
{"T", 'T'},
|
||||
{"Y", 'Y'},
|
||||
{"U", 'U'},
|
||||
{"I", 'I'},
|
||||
{"O", 'O'},
|
||||
{"P", 'P'},
|
||||
{"@", VK_OEM_3},
|
||||
{"[", VK_OEM_4},
|
||||
|
||||
// Row 4
|
||||
{"CAPS_LOCK", VK_CAPITAL},
|
||||
{"A", 'A'},
|
||||
{"S", 'S'},
|
||||
{"D", 'D'},
|
||||
{"F", 'F'},
|
||||
{"G", 'G'},
|
||||
{"H", 'H'},
|
||||
{"J", 'J'},
|
||||
{"K", 'K'},
|
||||
{"L", 'L'},
|
||||
{";", VK_OEM_PLUS},
|
||||
{":", VK_OEM_1},
|
||||
{"]", VK_OEM_6},
|
||||
{"ENTER", VK_RETURN},
|
||||
|
||||
// Row 5
|
||||
{"SHIFT", VK_SHIFT},
|
||||
{"Z", 'Z'},
|
||||
{"X", 'X'},
|
||||
{"C", 'C'},
|
||||
{"V", 'V'},
|
||||
{"B", 'B'},
|
||||
{"N", 'N'},
|
||||
{"M", 'M'},
|
||||
{",", VK_OEM_COMMA},
|
||||
{".", VK_OEM_PERIOD},
|
||||
{"SLASH", VK_OEM_2},
|
||||
{"BACKSLASH", VK_OEM_102},
|
||||
|
||||
// Row 6
|
||||
{"CONTROL", VK_CONTROL},
|
||||
{"L_WIN", VK_LWIN},
|
||||
{"ALT", VK_MENU},
|
||||
{"SPACE", VK_SPACE},
|
||||
{"R_WIN", VK_RWIN},
|
||||
{"MENU", VK_APPS},
|
||||
|
||||
// Other Keys
|
||||
// PrtSc is more important when making snapshots, therefore comment it as reserved
|
||||
//{"PRINT_SCREEN", VK_SNAPSHOT},
|
||||
{"SCROLL_LOCK", VK_SCROLL},
|
||||
{"PAUSE", VK_PAUSE},
|
||||
{"INSERT", VK_INSERT},
|
||||
{"DELETE", VK_DELETE},
|
||||
{"HOME", VK_HOME},
|
||||
{"END", VK_END},
|
||||
{"PAGE_UP", VK_PRIOR},
|
||||
{"PAGE_DOWN", VK_NEXT},
|
||||
|
||||
// Arrow Keys
|
||||
{"UPARROW", VK_UP},
|
||||
{"LEFTARROW", VK_LEFT},
|
||||
{"DOWNARROW", VK_DOWN},
|
||||
{"RIGHTARROW", VK_RIGHT},
|
||||
|
||||
// NUMPAD Keys
|
||||
{"NUM_LOCK", VK_NUMLOCK},
|
||||
{"DIVIDE", VK_DIVIDE},
|
||||
{"MULTIPLY", VK_MULTIPLY},
|
||||
{"SUBTRACT", VK_SUBTRACT},
|
||||
{"NUM7", VK_NUMPAD7},
|
||||
{"NUM8", VK_NUMPAD8},
|
||||
{"NUM9", VK_NUMPAD9},
|
||||
{"ADD", VK_ADD},
|
||||
{"NUM4", VK_NUMPAD4},
|
||||
{"NUM5", VK_NUMPAD5},
|
||||
{"NUM6", VK_NUMPAD6},
|
||||
{"NUM1", VK_NUMPAD1},
|
||||
{"NUM2", VK_NUMPAD2},
|
||||
{"NUM3", VK_NUMPAD3},
|
||||
{"NUM0", VK_NUMPAD0},
|
||||
{"DECIMAL", VK_DECIMAL},
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *string;
|
||||
SDL_GamepadButton button;
|
||||
} ConfigControllerButtons[] = {
|
||||
{"SDL_A", SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{"SDL_B", SDL_GAMEPAD_BUTTON_EAST},
|
||||
{"SDL_X", SDL_GAMEPAD_BUTTON_WEST},
|
||||
{"SDL_Y", SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{"SDL_BACK", SDL_GAMEPAD_BUTTON_BACK},
|
||||
{"SDL_GUIDE", SDL_GAMEPAD_BUTTON_GUIDE},
|
||||
{"SDL_START", SDL_GAMEPAD_BUTTON_START},
|
||||
{"SDL_LSTICK_PRESS", SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{"SDL_RSTICK_PRESS", SDL_GAMEPAD_BUTTON_RIGHT_STICK},
|
||||
{"SDL_LSHOULDER", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
||||
{"SDL_RSHOULDER", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
||||
{"SDL_DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||
{"SDL_DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||
{"SDL_DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||
{"SDL_DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||
{"SDL_MISC", SDL_GAMEPAD_BUTTON_MISC1},
|
||||
{"SDL_PADDLE1", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1},
|
||||
{"SDL_PADDLE2", SDL_GAMEPAD_BUTTON_LEFT_PADDLE1},
|
||||
{"SDL_PADDLE3", SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2},
|
||||
{"SDL_PADDLE4", SDL_GAMEPAD_BUTTON_LEFT_PADDLE2},
|
||||
{"SDL_TOUCHPAD", SDL_GAMEPAD_BUTTON_TOUCHPAD},
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *string;
|
||||
SDLAxis axis;
|
||||
} ConfigControllerAXIS[] = {
|
||||
{"SDL_LSTICK_LEFT", SDL_AXIS_LEFT_LEFT}, {"SDL_LSTICK_UP", SDL_AXIS_LEFT_UP}, {"SDL_LSTICK_DOWN", SDL_AXIS_LEFT_DOWN},
|
||||
{"SDL_LSTICK_RIGHT", SDL_AXIS_LEFT_RIGHT}, {"SDL_RSTICK_LEFT", SDL_AXIS_RIGHT_LEFT}, {"SDL_RSTICK_UP", SDL_AXIS_RIGHT_UP},
|
||||
{"SDL_RSTICK_DOWN", SDL_AXIS_RIGHT_DOWN}, {"SDL_RSTICK_RIGHT", SDL_AXIS_RIGHT_RIGHT}, {"SDL_LTRIGGER", SDL_AXIS_LTRIGGER_DOWN},
|
||||
{"SDL_RTRIGGER", SDL_AXIS_RTRIGGER_DOWN},
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *string;
|
||||
Scroll scroll;
|
||||
} ConfigMouseScroll[] = {
|
||||
{"SCROLL_UP", MOUSE_SCROLL_UP},
|
||||
{"SCROLL_DOWN", MOUSE_SCROLL_DOWN},
|
||||
};
|
||||
|
||||
struct MouseState {
|
||||
POINT Position;
|
||||
POINT RelativePosition;
|
||||
bool ScrolledUp;
|
||||
bool ScrolledDown;
|
||||
} currentMouseState, lastMouseState;
|
||||
Reference in New Issue
Block a user