mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
sdk: introduce Spice SDK (#676)
## Link to GitHub Issue or related Pull Request, if one exists
n/a
## Description of change
Adds a flat-C, headers-only library for writing DLL plugins with spice.
This is meant to be an alternative to writing applications over spice
API which doesn't suit some scenarios like writing custom
high-performance I/O modules.
All you have to do is:
1. Create a 32-bit or 64-bit DLL with `spice_sdk_entry_point` as a
DLLExport
1. Include `spicesdk.h`, and optionally `spicesdk_io.h` (see
`extras\sdk\include`)
1. `spice_sdk_entry_point` will be called when hooks get initialized.
Call `init` with valid parameters.
1. When `init` returns, `SPICE_SDK_V0` will be filled out with a series
of function pointers; your DLL can now start calling into it.
1. Compile your DLL and add it as a DLL hook (`-k`) in spice when
launching the game.
See `v0_cpp.cpp` for an example.
V0 implements the following functions:
```
log;
get_game_info;
get_avs_info;
get_button;
set_button;
get_analog;
set_analog;
get_light;
set_light;
set_touch;
clear_touch;
insert_card;
set_keypad;
```
V0 is focused on providing common utility functions needed in a lot of
DLL hooks (get AVS info, log messages to file), and implementing I/O.
In the future, we could have more interesting things like:
* scanning and modifying memory
* installing DLL hooks
* having direct hooks into I/O emulation modules
* getting full tape LEDs
* having a callback into DX9 `Present` call
* drawing an ImGui window
More detailed documentation is coming soon in form of a wiki page.
## Testing
See included sample DLL.
This commit is contained in:
@@ -607,6 +607,9 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
reader/structuredmessage.cpp
|
reader/structuredmessage.cpp
|
||||||
reader/crypt.cpp
|
reader/crypt.cpp
|
||||||
|
|
||||||
|
# sdk
|
||||||
|
sdk/sdk.cpp
|
||||||
|
|
||||||
# stubs
|
# stubs
|
||||||
stubs/stubs.cpp
|
stubs/stubs.cpp
|
||||||
|
|
||||||
@@ -860,6 +863,36 @@ if(NOT MSVC)
|
|||||||
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_flat_c.dll (32 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/flat_c/v0_flat_c.c)
|
||||||
|
add_library(spicetools_sdk_sample_v0_flat_c_32 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/flat_c/v0_flat_c.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES OUTPUT_NAME "sdk_sample_v0_flat_c")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_32 PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_flat_c.dll (64 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/flat_c/v0_flat_c.c)
|
||||||
|
add_library(spicetools_sdk_sample_v0_flat_c_64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/flat_c/v0_flat_c.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES OUTPUT_NAME "sdk_sample_v0_flat_c")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_flat_c_64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# sdk_sample_v0_cpp.dll (64 bit)
|
||||||
|
set(SOURCE_FILES sdk/sample/v0/cpp/v0_cpp.cpp)
|
||||||
|
add_library(spicetools_sdk_sample_v0_cpp_64 SHARED ${SOURCE_FILES} ${RESOURCE_FILES} sdk/sample/v0/cpp/v0_cpp.def)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES OUTPUT_NAME "sdk_sample_v0_cpp")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_sdk_sample_v0_cpp_64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
|
endif()
|
||||||
|
|
||||||
# output directories
|
# output directories
|
||||||
####################
|
####################
|
||||||
|
|
||||||
@@ -869,14 +902,14 @@ set_target_properties(spicetools_cfg spicetools_cfg_linux
|
|||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
||||||
|
|
||||||
# output 32bit
|
# output 32bit
|
||||||
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
|
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm spicetools_sdk_sample_v0_flat_c_32
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
||||||
|
|
||||||
# output 64bit
|
# output 64bit
|
||||||
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
|
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64 spicetools_sdk_sample_v0_flat_c_64 spicetools_sdk_sample_v0_cpp_64
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
||||||
|
|||||||
@@ -283,6 +283,16 @@ Python is the only one that is fully spec compliant.
|
|||||||
Other libraries may be missing features and contain bugs; please feel free to
|
Other libraries may be missing features and contain bugs; please feel free to
|
||||||
contribute code to fill the gaps if you work on a project using these libraries.
|
contribute code to fill the gaps if you work on a project using these libraries.
|
||||||
|
|
||||||
|
## Spice SDK (for DLL hooks / plugins)
|
||||||
|
|
||||||
|
As an alternative to Spice API, Spice SDK is available.
|
||||||
|
|
||||||
|
This is a flat C, header-only library that can be included in your DLL. Once
|
||||||
|
initialized, you can call directly into helper routines provided by Spicetools
|
||||||
|
executable, making low-latency and high-throughput interactions possible.
|
||||||
|
|
||||||
|
Check the documentation on the wiki for more details.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Unless otherwise noted, all files are licensed under the GPLv3.
|
Unless otherwise noted, all files are licensed under the GPLv3.
|
||||||
See the LICENSE file for the full license text.
|
See the LICENSE file for the full license text.
|
||||||
|
|||||||
+10
-14
@@ -68,8 +68,8 @@ DIST_FOLDER="./dist"
|
|||||||
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
||||||
DIST_NAME_EXTRAS="spice2x-$(date +%y)-$(date +%m)-$(date +%d)-full.zip"
|
DIST_NAME_EXTRAS="spice2x-$(date +%y)-$(date +%m)-$(date +%d)-full.zip"
|
||||||
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
|
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
|
||||||
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_cfg_linux spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_cpusbxpkm"
|
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_cfg_linux spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_cpusbxpkm spicetools_sdk_sample_v0_flat_c_32"
|
||||||
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64 spicetools_spice64_linux"
|
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64 spicetools_spice64_linux spicetools_sdk_sample_v0_flat_c_64 spicetools_sdk_sample_v0_cpp_64"
|
||||||
TARGETS_XP32="spicetools_cfg spicetools_spice"
|
TARGETS_XP32="spicetools_cfg spicetools_spice"
|
||||||
TARGETS_XP64="spicetools_spice64"
|
TARGETS_XP64="spicetools_spice64"
|
||||||
|
|
||||||
@@ -269,6 +269,8 @@ rm -rf ${OUTDIR_EXTRAS}
|
|||||||
mkdir -p ${OUTDIR_EXTRAS}
|
mkdir -p ${OUTDIR_EXTRAS}
|
||||||
mkdir -p ${OUTDIR_EXTRAS}/largeaddressaware
|
mkdir -p ${OUTDIR_EXTRAS}/largeaddressaware
|
||||||
mkdir -p ${OUTDIR_EXTRAS}/linux
|
mkdir -p ${OUTDIR_EXTRAS}/linux
|
||||||
|
mkdir -p ${OUTDIR_EXTRAS}/sdk/samples/32
|
||||||
|
mkdir -p ${OUTDIR_EXTRAS}/sdk/samples/64
|
||||||
if ((BUILD_XP > 0))
|
if ((BUILD_XP > 0))
|
||||||
then
|
then
|
||||||
mkdir -p ${OUTDIR_EXTRAS}/winxp
|
mkdir -p ${OUTDIR_EXTRAS}/winxp
|
||||||
@@ -281,16 +283,8 @@ then
|
|||||||
cp ${BUILDDIR_32}/spicetools/spicecfg-pdb.pdb ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/spicecfg-pdb.pdb ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/spice-pdb.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice-pdb.exe ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/spice-pdb.pdb ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice-pdb.pdb ${OUTDIR} 2>/dev/null
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
|
|
||||||
cp ${BUILDDIR_64}/spicetools/64/spice64-pdb.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/spice64-pdb.exe ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/spice64-pdb.pdb ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/spice64-pdb.pdb ${OUTDIR} 2>/dev/null
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/kbt.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/kld.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null
|
|
||||||
else
|
else
|
||||||
# release files
|
# release files
|
||||||
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
||||||
@@ -298,16 +292,15 @@ else
|
|||||||
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR_EXTRAS}/largeaddressaware/spice.exe 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR_EXTRAS}/largeaddressaware/spice.exe 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/spice_linux.exe ${OUTDIR_EXTRAS}/linux/spice.exe 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/spice_linux.exe ${OUTDIR_EXTRAS}/linux/spice.exe 2>/dev/null
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
|
|
||||||
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/spice64_linux.exe ${OUTDIR_EXTRAS}/linux/spice64.exe 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/spice64_linux.exe ${OUTDIR_EXTRAS}/linux/spice64.exe 2>/dev/null
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/kbt.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/kld.dll ${OUTDIR}/stubs/64 2>/dev/null
|
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null
|
cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
|
cp ${BUILDDIR_32}/spicetools/32/sdk_sample_v0_flat_c.dll ${OUTDIR_EXTRAS}/sdk/samples/32/v0_flat_c.dll 2>/dev/null
|
||||||
|
cp ${BUILDDIR_64}/spicetools/64/sdk_sample_v0_flat_c.dll ${OUTDIR_EXTRAS}/sdk/samples/64/v0_flat_c.dll 2>/dev/null
|
||||||
|
cp ${BUILDDIR_64}/spicetools/64/sdk_sample_v0_cpp.dll ${OUTDIR_EXTRAS}/sdk/samples/64/v0_cpp.dll 2>/dev/null
|
||||||
if ((BUILD_XP > 0))
|
if ((BUILD_XP > 0))
|
||||||
then
|
then
|
||||||
cp ${BUILDDIR_WINXP_32}/spicetools/spicecfg.exe ${OUTDIR_EXTRAS}/winxp 2>/dev/null
|
cp ${BUILDDIR_WINXP_32}/spicetools/spicecfg.exe ${OUTDIR_EXTRAS}/winxp 2>/dev/null
|
||||||
@@ -326,6 +319,9 @@ then
|
|||||||
echo "WARNING: Couldn't get git to create the archive. Is this a git repository?"
|
echo "WARNING: Couldn't get git to create the archive. Is this a git repository?"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# sdk headers
|
||||||
|
cp -r ./sdk/include ${OUTDIR_EXTRAS}/sdk
|
||||||
|
|
||||||
# copy resources
|
# copy resources
|
||||||
rm -rf ${OUTDIR_EXTRAS}/api
|
rm -rf ${OUTDIR_EXTRAS}/api
|
||||||
mkdir ${OUTDIR_EXTRAS}/api
|
mkdir ${OUTDIR_EXTRAS}/api
|
||||||
|
|||||||
@@ -98,6 +98,7 @@
|
|||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
#include "rawinput/touch.h"
|
#include "rawinput/touch.h"
|
||||||
#include "reader/reader.h"
|
#include "reader/reader.h"
|
||||||
|
#include "sdk/sdk.h"
|
||||||
#include "stubs/stubs.h"
|
#include "stubs/stubs.h"
|
||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
#include "util/cpuutils.h"
|
#include "util/cpuutils.h"
|
||||||
@@ -2358,6 +2359,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
bt5api_hook(module);
|
bt5api_hook(module);
|
||||||
|
sdk::register_sdk_hooks(hook, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2392,6 +2394,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bt5api_init();
|
bt5api_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// init SDK
|
||||||
|
sdk::init_sdk_modules();
|
||||||
|
|
||||||
// API
|
// API
|
||||||
if (api_enable || std::min(api_serial_port.size(), api_serial_baud.size()) > 0) {
|
if (api_enable || std::min(api_serial_port.size(), api_serial_baud.size()) > 0) {
|
||||||
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
||||||
@@ -2499,6 +2504,8 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bt5api_dispose();
|
bt5api_dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdk::fini_sdk_modules();
|
||||||
|
|
||||||
// stop raw input
|
// stop raw input
|
||||||
RI_MGR.reset();
|
RI_MGR.reset();
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "launcher.h"
|
#include "launcher.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "nvapi/nvapi.h"
|
#include "nvapi/nvapi.h"
|
||||||
|
#include "sdk/sdk.h"
|
||||||
|
|
||||||
namespace launcher {
|
namespace launcher {
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ namespace launcher {
|
|||||||
// therefore, subsystems need to be guarded against multiple unload attempts
|
// therefore, subsystems need to be guarded against multiple unload attempts
|
||||||
log_info("launcher", "stopping subsystems");
|
log_info("launcher", "stopping subsystems");
|
||||||
|
|
||||||
|
sdk::fini_sdk_modules();
|
||||||
|
|
||||||
// reset monitor settings
|
// reset monitor settings
|
||||||
reset_monitor_on_exit();
|
reset_monitor_on_exit();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef SPICE_SDK_H
|
||||||
|
#define SPICE_SDK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define SPICE_SDK_ENTRY_POINT extern "C" __declspec(dllexport) int __cdecl
|
||||||
|
#else
|
||||||
|
#define SPICE_SDK_ENTRY_POINT __declspec(dllexport) int __cdecl
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum SPICE_SDK_STATUS_CODE {
|
||||||
|
SPICE_SDK_STATUS_SUCCESS = 0,
|
||||||
|
|
||||||
|
// 000: generic
|
||||||
|
SPICE_SDK_STATUS_GENERIC_ERROR = 1,
|
||||||
|
SPICE_SDK_STATUS_NOT_INITIALIZED = 2,
|
||||||
|
SPICE_SDK_STATUS_NOT_SUPPORTED = 3,
|
||||||
|
SPICE_SDK_STATUS_TOO_SMALL = 4,
|
||||||
|
SPICE_SDK_STATUS_TOO_LATE = 5,
|
||||||
|
|
||||||
|
// 1000: invalid args
|
||||||
|
SPICE_SDK_STATUS_INVALID_ARGUMENT_1 = 1001,
|
||||||
|
SPICE_SDK_STATUS_INVALID_ARGUMENT_2 = 1002,
|
||||||
|
SPICE_SDK_STATUS_INVALID_ARGUMENT_3 = 1003,
|
||||||
|
SPICE_SDK_STATUS_INVALID_ARGUMENT_4 = 1004,
|
||||||
|
SPICE_SDK_STATUS_INVALID_ARGUMENT_5 = 1005,
|
||||||
|
|
||||||
|
} SPICE_SDK_STATUS_CODE;
|
||||||
|
|
||||||
|
typedef enum SPICE_SDK_LOG_LEVEL {
|
||||||
|
SPICE_SDK_LOG_LEVEL_MISC = 0,
|
||||||
|
SPICE_SDK_LOG_LEVEL_INFO = 1,
|
||||||
|
SPICE_SDK_LOG_LEVEL_WARNING = 2,
|
||||||
|
SPICE_SDK_LOG_LEVEL_FATAL = 3,
|
||||||
|
} SPICE_SDK_LOG_LEVEL;
|
||||||
|
|
||||||
|
typedef struct SPICE_SDK_TOUCH_POINT {
|
||||||
|
uint32_t id;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} SPICE_SDK_TOUCH_POINT;
|
||||||
|
|
||||||
|
typedef struct SPICE_SDK_GAME_INFO {
|
||||||
|
char name[64]; // null-terminated
|
||||||
|
} SPICE_SDK_GAME_INFO;
|
||||||
|
|
||||||
|
typedef struct SPICE_SDK_AVS_INFO {
|
||||||
|
char model[4]; // "MDX", null-terminated
|
||||||
|
char dest; // J
|
||||||
|
char spec; // A
|
||||||
|
char rev; // A
|
||||||
|
char ext[11]; // "2025061002", null-terminated
|
||||||
|
} SPICE_SDK_AVS_INFO;
|
||||||
|
|
||||||
|
// get_game_info (v0.1 and up)
|
||||||
|
//
|
||||||
|
// get info about the currently running game
|
||||||
|
//
|
||||||
|
// info: receives game info
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_get_game_info_func)(
|
||||||
|
SPICE_SDK_GAME_INFO *info
|
||||||
|
);
|
||||||
|
|
||||||
|
// get_avs_info (v0.1 and up)
|
||||||
|
//
|
||||||
|
// get AVS info (model, dest, spec, rev, ext)
|
||||||
|
//
|
||||||
|
// info: receives AVS info
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_get_avs_info_func)(
|
||||||
|
SPICE_SDK_AVS_INFO *info
|
||||||
|
);
|
||||||
|
|
||||||
|
// log (v0.1 and up)
|
||||||
|
// logs a message to the log
|
||||||
|
// writing a FATAL message will terminate spice, only use in catastrophic failure
|
||||||
|
//
|
||||||
|
// level: see log level enum
|
||||||
|
// module: short string that identifies the facility / module / submodule
|
||||||
|
// message: the message to log
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_log_func)(
|
||||||
|
SPICE_SDK_LOG_LEVEL level,
|
||||||
|
const char *module,
|
||||||
|
const char *message
|
||||||
|
);
|
||||||
|
|
||||||
|
// get_button (v0.1 and up)
|
||||||
|
// gets the button state
|
||||||
|
//
|
||||||
|
// button_id: ID of the button; see spicesdk_io.h for named values
|
||||||
|
// pressed: (optional) is the button pressed?
|
||||||
|
// velocity: (optional) MIDI velocity of the button
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_get_button_func)(
|
||||||
|
uint32_t button_id,
|
||||||
|
bool *pressed,
|
||||||
|
float *velocity
|
||||||
|
);
|
||||||
|
|
||||||
|
// set_button (v0.1 and up)
|
||||||
|
// sets or clears the button override
|
||||||
|
//
|
||||||
|
// make sure to hold the button long enough for the game's I/O engine to pick up
|
||||||
|
// usually, one or two frames
|
||||||
|
//
|
||||||
|
// button_id: ID of the button; see spicesdk_io.h for named values
|
||||||
|
// pressed: true to set the button override (permanently set the button to be ON until cleared),
|
||||||
|
// false to clear the override (allow user's controller to provide input again)
|
||||||
|
// velocity: MIDI velocity of the button; only valid when pressed is true
|
||||||
|
// can be between 0.0 and 1.0, inclusive
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_set_button_func)(
|
||||||
|
uint32_t button_id,
|
||||||
|
bool pressed,
|
||||||
|
float velocity
|
||||||
|
);
|
||||||
|
|
||||||
|
// get_analog (v0.1 and up)
|
||||||
|
// gets the analog state
|
||||||
|
//
|
||||||
|
// button_id: ID of the button; see spicesdk_io.h for named values
|
||||||
|
// value: receives the state of the analog
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_get_analog_func)(
|
||||||
|
uint32_t analog_id,
|
||||||
|
float *value
|
||||||
|
);
|
||||||
|
|
||||||
|
// set_analog (v0.1 and up)
|
||||||
|
// sets or clears the analog override
|
||||||
|
//
|
||||||
|
// analog_id: ID of the analog; see spicesdk_io.h for named values
|
||||||
|
// override_active: true to set override (gain exclusive control)
|
||||||
|
// false to clear it (allow user's controller provide input again)
|
||||||
|
// value: value of the analog; only valid when override_active is true
|
||||||
|
// can be between 0.0 and 1.0, inclusive
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_set_analog_func)(
|
||||||
|
uint32_t analog_id,
|
||||||
|
bool override_active,
|
||||||
|
float value
|
||||||
|
);
|
||||||
|
|
||||||
|
// get_light (v0.1 and up)
|
||||||
|
// gets the last observed value of a light
|
||||||
|
//
|
||||||
|
// light_id: ID of the light; see spicesdk_io.h for named values
|
||||||
|
// value: output parameter for the light value; 0.0 to 1.0
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_get_light_func)(
|
||||||
|
uint32_t light_id,
|
||||||
|
float *value
|
||||||
|
);
|
||||||
|
|
||||||
|
// set_light (v0.1 and up)
|
||||||
|
// sets or clears the light override
|
||||||
|
//
|
||||||
|
// light_id: ID of the light; see spicesdk_io.h for named values
|
||||||
|
// light_value: output parameter for the light value; 0.0 to 1.0
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_set_light_func)(
|
||||||
|
uint32_t light_id,
|
||||||
|
bool override_active,
|
||||||
|
float light_value
|
||||||
|
);
|
||||||
|
|
||||||
|
// set_touch (v0.1 and up)
|
||||||
|
// adds or updates touch points
|
||||||
|
//
|
||||||
|
// points: array of touch points to add or update
|
||||||
|
// count: number of touch points in the array
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_set_touch_func)(
|
||||||
|
const SPICE_SDK_TOUCH_POINT *points,
|
||||||
|
uint32_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
// clear_touch (v0.1 and up)
|
||||||
|
// clears touch points (i.e., no longer being touched)
|
||||||
|
//
|
||||||
|
// ids: array of touch point IDs to clear
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_clear_touch_func)(
|
||||||
|
const uint32_t *ids,
|
||||||
|
uint32_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
// insert_card (v0.1 and up)
|
||||||
|
// simulates inserting an e-amuse card with the given ID
|
||||||
|
//
|
||||||
|
// unit: 0 for player 1, 1 for player 2
|
||||||
|
// card_id: null-terminated string of the card ID
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_insert_card_func)(
|
||||||
|
uint8_t unit,
|
||||||
|
const char *card_id
|
||||||
|
);
|
||||||
|
|
||||||
|
// set_keypad (v0.1 and up)
|
||||||
|
// sets keypad state
|
||||||
|
//
|
||||||
|
// make sure to hold the button long enough for the game to pick up
|
||||||
|
// 70ms is usually sufficient, except for DDR which needs 150ms
|
||||||
|
//
|
||||||
|
// unit: 0 for player 1, 1 for player 2
|
||||||
|
// key: '0' to '9' for numbers, 'A' for 00, 'D' for decimal point, 0 or '\0' to release all keys
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_set_keypad_func)(
|
||||||
|
uint8_t unit,
|
||||||
|
char key
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct SPICE_SDK_V0 {
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
spice_sdk_log_func *log;
|
||||||
|
|
||||||
|
spice_sdk_get_game_info_func *get_game_info;
|
||||||
|
spice_sdk_get_avs_info_func *get_avs_info;
|
||||||
|
|
||||||
|
spice_sdk_get_button_func *get_button;
|
||||||
|
spice_sdk_set_button_func *set_button;
|
||||||
|
|
||||||
|
spice_sdk_get_analog_func *get_analog;
|
||||||
|
spice_sdk_set_analog_func *set_analog;
|
||||||
|
|
||||||
|
spice_sdk_get_light_func *get_light;
|
||||||
|
spice_sdk_set_light_func *set_light;
|
||||||
|
|
||||||
|
spice_sdk_set_touch_func *set_touch;
|
||||||
|
spice_sdk_clear_touch_func *clear_touch;
|
||||||
|
|
||||||
|
spice_sdk_insert_card_func *insert_card;
|
||||||
|
spice_sdk_set_keypad_func *set_keypad;
|
||||||
|
|
||||||
|
} SPICE_SDK_V0;
|
||||||
|
|
||||||
|
typedef void (__cdecl spice_sdk_destroy_callback_func)(
|
||||||
|
void
|
||||||
|
);
|
||||||
|
|
||||||
|
// init (v0.1 and up)
|
||||||
|
//
|
||||||
|
// version: supply 0
|
||||||
|
// destroy_callback: supply a function pointer that will be called when spice
|
||||||
|
// is shutting down
|
||||||
|
// sdk_functions: supply a pointer to SPICE_SDK_V0; ensure size field is initialized
|
||||||
|
// to sizeof(SPICE_SDK_V0) before calling this function
|
||||||
|
|
||||||
|
typedef SPICE_SDK_STATUS_CODE (__cdecl spice_sdk_init_func)(
|
||||||
|
uint32_t version,
|
||||||
|
spice_sdk_destroy_callback_func *destroy_callback,
|
||||||
|
void *sdk_functions
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef int (__cdecl spice_sdk_entry_point_func)(
|
||||||
|
spice_sdk_init_func *init
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SPICE_SDK_H
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "sdk/include/spicesdk.h"
|
||||||
|
#include "sdk/include/spicesdk_io.h"
|
||||||
|
|
||||||
|
#define LOG_INFO(message) spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0_cpp", message)
|
||||||
|
|
||||||
|
static SPICE_SDK_V0 spice = {};
|
||||||
|
static spice_sdk_destroy_callback_func destroy_callback;
|
||||||
|
static std::jthread worker_thread;
|
||||||
|
|
||||||
|
static void worker_thread_main(std::stop_token stop_token) {
|
||||||
|
while (!stop_token.stop_requested()) {
|
||||||
|
|
||||||
|
static bool state = false;
|
||||||
|
bool new_state;
|
||||||
|
spice.get_button(IIDX_Button_P1_Start, &new_state, nullptr);
|
||||||
|
if (!state && new_state) {
|
||||||
|
LOG_INFO("user pressed P1 Start button!");
|
||||||
|
}
|
||||||
|
state = new_state;
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_ENTRY_POINT
|
||||||
|
spice_sdk_entry_point(
|
||||||
|
spice_sdk_init_func *init
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SPICE_SDK_STATUS_CODE status;
|
||||||
|
|
||||||
|
spice.size = sizeof(spice);
|
||||||
|
status = init(0, destroy_callback, &spice);
|
||||||
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("plugin loaded");
|
||||||
|
worker_thread = std::jthread(worker_thread_main);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__cdecl
|
||||||
|
destroy_callback(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LOG_INFO("plugin unloading");
|
||||||
|
if (worker_thread.joinable()) {
|
||||||
|
worker_thread.request_stop();
|
||||||
|
worker_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
LIBRARY sdk_sample_v0_cpp
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
spice_sdk_entry_point
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
#include "sdk/include/spicesdk.h"
|
||||||
|
#include "sdk/include/spicesdk_io.h"
|
||||||
|
|
||||||
|
static SPICE_SDK_V0 spice;
|
||||||
|
|
||||||
|
static spice_sdk_destroy_callback_func destroy_callback;
|
||||||
|
|
||||||
|
static void test_logging();
|
||||||
|
static void test_game_info();
|
||||||
|
static void test_avs_info();
|
||||||
|
|
||||||
|
static void get_buttons();
|
||||||
|
static void set_buttons();
|
||||||
|
static void clear_buttons();
|
||||||
|
|
||||||
|
static void get_analogs();
|
||||||
|
static void set_analogs();
|
||||||
|
static void clear_analogs();
|
||||||
|
|
||||||
|
static void get_lights();
|
||||||
|
static void set_lights();
|
||||||
|
static void clear_lights();
|
||||||
|
|
||||||
|
static void set_touch();
|
||||||
|
static void clear_touch();
|
||||||
|
static void insert_card();
|
||||||
|
static void set_keypad();
|
||||||
|
static void clear_keypad();
|
||||||
|
|
||||||
|
static HANDLE worker_stop_event;
|
||||||
|
static HANDLE worker_handle;
|
||||||
|
static unsigned __stdcall worker_thread(void *arg);
|
||||||
|
|
||||||
|
// this sample assumes that the game is IIDX, but it doesn't check for it.
|
||||||
|
|
||||||
|
SPICE_SDK_ENTRY_POINT
|
||||||
|
spice_sdk_entry_point(
|
||||||
|
spice_sdk_init_func *init
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SPICE_SDK_STATUS_CODE status;
|
||||||
|
|
||||||
|
memset(&spice, 0, sizeof(spice));
|
||||||
|
spice.size = sizeof(spice);
|
||||||
|
status = init(0, destroy_callback, &spice);
|
||||||
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "plugin loaded");
|
||||||
|
test_logging();
|
||||||
|
test_game_info();
|
||||||
|
test_avs_info();
|
||||||
|
|
||||||
|
worker_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!worker_stop_event) {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "failed to create worker stop event");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_handle = (HANDLE)_beginthreadex(
|
||||||
|
NULL, // security
|
||||||
|
0, // stack size
|
||||||
|
worker_thread, // function
|
||||||
|
NULL, // argument
|
||||||
|
0, // flags
|
||||||
|
NULL // thread id
|
||||||
|
);
|
||||||
|
if (!worker_handle) {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "failed to create worker thread");
|
||||||
|
CloseHandle(worker_stop_event);
|
||||||
|
worker_stop_event = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
__cdecl
|
||||||
|
destroy_callback(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "plugin unloaded");
|
||||||
|
if (worker_stop_event) {
|
||||||
|
SetEvent(worker_stop_event);
|
||||||
|
}
|
||||||
|
if (worker_handle) {
|
||||||
|
WaitForSingleObject(worker_handle, INFINITE);
|
||||||
|
CloseHandle(worker_handle);
|
||||||
|
worker_handle = NULL;
|
||||||
|
}
|
||||||
|
if (worker_stop_event) {
|
||||||
|
CloseHandle(worker_stop_event);
|
||||||
|
worker_stop_event = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned __stdcall worker_thread(void *arg) {
|
||||||
|
int phase = 0;
|
||||||
|
while (WaitForSingleObject(worker_stop_event, 0) == WAIT_TIMEOUT) {
|
||||||
|
phase += 1;
|
||||||
|
switch (phase) {
|
||||||
|
case 1:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "get buttons...");
|
||||||
|
get_buttons();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "set buttons...");
|
||||||
|
set_buttons();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "clear buttons...");
|
||||||
|
clear_buttons();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "get analogs...");
|
||||||
|
get_analogs();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "set analogs...");
|
||||||
|
set_analogs();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "clear analogs...");
|
||||||
|
clear_analogs();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "get lights...");
|
||||||
|
get_lights();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "set lights...");
|
||||||
|
set_lights();
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "clear lights...");
|
||||||
|
clear_lights();
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "set touch...");
|
||||||
|
set_touch();
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "clear touch...");
|
||||||
|
clear_touch();
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "insert card...");
|
||||||
|
insert_card();
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "set keypad...");
|
||||||
|
set_keypad();
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "clear keypad...");
|
||||||
|
clear_keypad();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
phase = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (phase != 0) {
|
||||||
|
WaitForSingleObject(worker_stop_event, 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_logging() {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_MISC, "sample_v0", "this is a misc message");
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", "this is an info message");
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "this is a warning message");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_game_info() {
|
||||||
|
SPICE_SDK_GAME_INFO info;
|
||||||
|
SPICE_SDK_STATUS_CODE status;
|
||||||
|
|
||||||
|
status = spice.get_game_info(&info);
|
||||||
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "get_game_info failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char log_message[128];
|
||||||
|
snprintf(log_message, sizeof(log_message), "game info - name: %s", info.name);
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", log_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_avs_info() {
|
||||||
|
SPICE_SDK_AVS_INFO info;
|
||||||
|
SPICE_SDK_STATUS_CODE status;
|
||||||
|
|
||||||
|
status = spice.get_avs_info(&info);
|
||||||
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "get_avs_info failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char log_message[128];
|
||||||
|
snprintf(
|
||||||
|
log_message,
|
||||||
|
sizeof(log_message),
|
||||||
|
"avs - model: %s, dest: %c, spec: %c, rev: %c, ext: %s",
|
||||||
|
info.model, info.dest, info.spec, info.rev, info.ext);
|
||||||
|
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", log_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_buttons() {
|
||||||
|
bool pressed;
|
||||||
|
float velocity;
|
||||||
|
spice.get_button(IIDX_Button_P1_Headphone, &pressed, &velocity);
|
||||||
|
|
||||||
|
char log_message[128];
|
||||||
|
snprintf(
|
||||||
|
log_message,
|
||||||
|
sizeof(log_message),
|
||||||
|
"button P1_Headphone pressed: %s, velocity: %.2f",
|
||||||
|
pressed ? "ON" : "off", velocity);
|
||||||
|
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", log_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_buttons() {
|
||||||
|
spice.set_button(IIDX_Button_P1_1, true, 0.3f);
|
||||||
|
spice.set_button(IIDX_Button_P1_3, true, 0.5f);
|
||||||
|
spice.set_button(IIDX_Button_P1_5, true, 0.7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_buttons() {
|
||||||
|
spice.set_button(IIDX_Button_P1_1, false, 0.f);
|
||||||
|
spice.set_button(IIDX_Button_P1_3, false, 0.f);
|
||||||
|
spice.set_button(IIDX_Button_P1_5, false, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_analogs() {
|
||||||
|
float value;
|
||||||
|
spice.get_analog(IIDX_Analog_TT_P1, &value);
|
||||||
|
|
||||||
|
char log_message[128];
|
||||||
|
snprintf(
|
||||||
|
log_message,
|
||||||
|
sizeof(log_message),
|
||||||
|
"analog TT_P1: %.2f",
|
||||||
|
value);
|
||||||
|
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", log_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_analogs() {
|
||||||
|
spice.set_analog(IIDX_Analog_TT_P1, true, 0.25f);
|
||||||
|
spice.set_analog(IIDX_Analog_TT_P2, true, 0.75f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_analogs() {
|
||||||
|
spice.set_analog(IIDX_Analog_TT_P1, false, 0.f);
|
||||||
|
spice.set_analog(IIDX_Analog_TT_P2, false, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_lights() {
|
||||||
|
float value;
|
||||||
|
SPICE_SDK_STATUS_CODE status;
|
||||||
|
|
||||||
|
status = spice.get_light(IIDX_Light_TT_P1_Resistance, &value);
|
||||||
|
if (status == SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
char log_message[64];
|
||||||
|
snprintf(log_message, sizeof(log_message), "P1 TT resistance value: %.2f", value);
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_INFO, "sample_v0", log_message);
|
||||||
|
} else {
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", "get_light failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_lights() {
|
||||||
|
spice.set_light(IIDX_Light_P1_Start, true, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_lights() {
|
||||||
|
spice.set_light(IIDX_Light_P1_Start, false, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_touch() {
|
||||||
|
SPICE_SDK_TOUCH_POINT points[2] = {
|
||||||
|
{ .id = 1, .x = 100, .y = 200 },
|
||||||
|
{ .id = 2, .x = 300, .y = 400 },
|
||||||
|
};
|
||||||
|
spice.set_touch(points, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_touch() {
|
||||||
|
uint32_t ids[2] = { 1, 2 };
|
||||||
|
spice.clear_touch(ids, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_card() {
|
||||||
|
spice.insert_card(0, "E004010000001234");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_keypad() {
|
||||||
|
SPICE_SDK_STATUS_CODE ret = spice.set_keypad(0, '3');
|
||||||
|
if (ret != SPICE_SDK_STATUS_SUCCESS) {
|
||||||
|
char log_message[64];
|
||||||
|
snprintf(log_message, sizeof(log_message), "set_keypad failed: %d", ret);
|
||||||
|
spice.log(SPICE_SDK_LOG_LEVEL_WARNING, "sample_v0", log_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_keypad() {
|
||||||
|
spice.set_keypad(0, 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
LIBRARY sdk_sample_v0_flat_c
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
spice_sdk_entry_point
|
||||||
@@ -0,0 +1,595 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
|
||||||
|
#include "sdk.h"
|
||||||
|
#include "avs/game.h"
|
||||||
|
#include "games/io.h"
|
||||||
|
#include "launcher/launcher.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#include "sdk/include/spicesdk.h"
|
||||||
|
#include "touch/touch.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
namespace sdk {
|
||||||
|
|
||||||
|
static spice_sdk_init_func sdk_init;
|
||||||
|
static spice_sdk_log_func sdk_log;
|
||||||
|
static spice_sdk_get_avs_info_func sdk_get_avs_info;
|
||||||
|
static spice_sdk_get_game_info_func sdk_get_game_info;
|
||||||
|
static spice_sdk_get_button_func sdk_get_button;
|
||||||
|
static spice_sdk_set_button_func sdk_set_button;
|
||||||
|
static spice_sdk_get_analog_func sdk_get_analog;
|
||||||
|
static spice_sdk_set_analog_func sdk_set_analog;
|
||||||
|
static spice_sdk_get_light_func sdk_get_light;
|
||||||
|
static spice_sdk_set_light_func sdk_set_light;
|
||||||
|
static spice_sdk_set_touch_func sdk_set_touch;
|
||||||
|
static spice_sdk_clear_touch_func sdk_clear_touch;
|
||||||
|
static spice_sdk_insert_card_func sdk_insert_card;
|
||||||
|
static spice_sdk_set_keypad_func sdk_set_keypad;
|
||||||
|
|
||||||
|
struct SdkModule {
|
||||||
|
std::string dll;
|
||||||
|
HINSTANCE module;
|
||||||
|
};
|
||||||
|
|
||||||
|
// DLLs
|
||||||
|
static int sdk_modules_count = 0;
|
||||||
|
static std::vector<SdkModule> sdk_modules_list;
|
||||||
|
static std::shared_mutex sdk_global_mutex;
|
||||||
|
|
||||||
|
// internal
|
||||||
|
static bool sdk_initialized = false;
|
||||||
|
static bool sdk_shutting_down = false;
|
||||||
|
static std::vector<Button> *buttons;
|
||||||
|
static std::vector<Analog> *analogs;
|
||||||
|
static std::vector<Light> *lights;
|
||||||
|
|
||||||
|
// callbacks
|
||||||
|
static std::mutex sdk_callback_registration_mutex;
|
||||||
|
static std::vector<spice_sdk_destroy_callback_func *> callbacks_destroy;
|
||||||
|
|
||||||
|
void register_sdk_hooks(std::string dll, HINSTANCE module) {
|
||||||
|
sdk_modules_list.emplace_back(std::move(dll), module);
|
||||||
|
sdk_modules_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_sdk_modules() {
|
||||||
|
if (sdk_modules_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare
|
||||||
|
buttons = games::get_buttons(eamuse_get_game());
|
||||||
|
analogs = games::get_analogs(eamuse_get_game());
|
||||||
|
lights = games::get_lights(eamuse_get_game());
|
||||||
|
|
||||||
|
// under exclusive lock, mark the SDK helpers as being available
|
||||||
|
{
|
||||||
|
std::unique_lock lock(sdk_global_mutex);
|
||||||
|
sdk_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// without any locks, call into each DLL; this may call back into SDK functions
|
||||||
|
for (auto &module : sdk_modules_list) {
|
||||||
|
// get a pointer to dll's spice_sdk_entry_point
|
||||||
|
const auto entry_point = reinterpret_cast<spice_sdk_entry_point_func *>(
|
||||||
|
GetProcAddress(module.module, "spice_sdk_entry_point"));
|
||||||
|
if (!entry_point) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call into it on this thread
|
||||||
|
log_info("sdk", "registering SDK hooks for {}", module.dll);
|
||||||
|
const auto ret = entry_point(sdk_init);
|
||||||
|
log_info("sdk", "spice_sdk_entry_point returned {}", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fini_sdk_modules() {
|
||||||
|
// prevent multiple calls and further calls into sdk_init
|
||||||
|
{
|
||||||
|
std::unique_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sdk_shutting_down = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call into destroy callback of each DLL
|
||||||
|
// this may call back into SDK functions (e.g., for logging)
|
||||||
|
// so we leave sdk_initialized as-is
|
||||||
|
{
|
||||||
|
log_info("sdk", "calling destroy callbacks...");
|
||||||
|
std::lock_guard lock(sdk_callback_registration_mutex);
|
||||||
|
for (const auto& destroy : callbacks_destroy) {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// under exclusive lock, mark the SDK functions as no longer available
|
||||||
|
{
|
||||||
|
std::unique_lock lock(sdk_global_mutex);
|
||||||
|
sdk_initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_init(
|
||||||
|
uint32_t version,
|
||||||
|
spice_sdk_destroy_callback_func *destroy_callback,
|
||||||
|
void *sdk_functions
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (sdk_shutting_down || !sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size;
|
||||||
|
if (version != 0) {
|
||||||
|
log_warning("sdk", "sdk_init returning NOT_SUPPORTED due to invalid version: {}", version);
|
||||||
|
return SPICE_SDK_STATUS_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!destroy_callback) {
|
||||||
|
log_warning("sdk", "sdk_init returning INVALID_ARGUMENT_2 due to invalid destroy_callback pointer");
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
if (!sdk_functions) {
|
||||||
|
log_warning("sdk", "sdk_init returning INVALID_ARGUMENT_3 due to invalid sdk_functions pointer");
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *v0 = reinterpret_cast<SPICE_SDK_V0 *>(sdk_functions);
|
||||||
|
if (v0->size < RTL_SIZEOF_THROUGH_FIELD(SPICE_SDK_V0, set_keypad)) {
|
||||||
|
log_warning("sdk", "sdk_init returning TOO_SMALL due to size field of SPICE_SDK_V0 not being set");
|
||||||
|
return SPICE_SDK_STATUS_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are trusting the size passed in by the caller
|
||||||
|
size = v0->size;
|
||||||
|
memset(v0, 0, size);
|
||||||
|
v0->size = size;
|
||||||
|
|
||||||
|
v0->log = sdk_log;
|
||||||
|
v0->get_game_info = sdk_get_game_info;
|
||||||
|
v0->get_avs_info = sdk_get_avs_info;
|
||||||
|
v0->get_button = sdk_get_button;
|
||||||
|
v0->set_button = sdk_set_button;
|
||||||
|
v0->get_analog = sdk_get_analog;
|
||||||
|
v0->set_analog = sdk_set_analog;
|
||||||
|
v0->get_light = sdk_get_light;
|
||||||
|
v0->set_light = sdk_set_light;
|
||||||
|
v0->set_touch = sdk_set_touch;
|
||||||
|
v0->clear_touch = sdk_clear_touch;
|
||||||
|
v0->insert_card = sdk_insert_card;
|
||||||
|
v0->set_keypad = sdk_set_keypad;
|
||||||
|
// end of 0.1
|
||||||
|
// any newer minor iterations will need to check the size
|
||||||
|
|
||||||
|
{
|
||||||
|
// destroy callbacks are only called upon successful return from this routine
|
||||||
|
std::lock_guard lock(sdk_callback_registration_mutex);
|
||||||
|
callbacks_destroy.push_back(destroy_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("sdk", "sdk_init returning SUCCESS");
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_log(
|
||||||
|
SPICE_SDK_LOG_LEVEL level,
|
||||||
|
const char *facility,
|
||||||
|
const char *message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (facility == nullptr) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string facility_str = fmt::format("sdk::{}", facility);
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case SPICE_SDK_LOG_LEVEL_MISC:
|
||||||
|
log_misc(facility_str.c_str(), "{}", message);
|
||||||
|
break;
|
||||||
|
case SPICE_SDK_LOG_LEVEL_INFO:
|
||||||
|
log_info(facility_str.c_str(), "{}", message);
|
||||||
|
break;
|
||||||
|
case SPICE_SDK_LOG_LEVEL_WARNING:
|
||||||
|
log_warning(facility_str.c_str(), "{}", message);
|
||||||
|
break;
|
||||||
|
case SPICE_SDK_LOG_LEVEL_FATAL:
|
||||||
|
log_fatal(facility_str.c_str(), "{}", message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_get_avs_info(
|
||||||
|
SPICE_SDK_AVS_INFO *info
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
// MDXJAA2025061002
|
||||||
|
strncpy(info->model, avs::game::MODEL, sizeof(info->model));
|
||||||
|
info->dest = avs::game::DEST[0];
|
||||||
|
info->spec = avs::game::SPEC[0];
|
||||||
|
info->rev = avs::game::REV[0];
|
||||||
|
strncpy(info->ext, avs::game::EXT, sizeof(info->ext));
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_get_game_info(
|
||||||
|
SPICE_SDK_GAME_INFO *info
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*info = {};
|
||||||
|
|
||||||
|
const std::string game_name = eamuse_get_game();
|
||||||
|
strncpy(info->name, game_name.c_str(), sizeof(info->name));
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_get_button (
|
||||||
|
uint32_t button_id,
|
||||||
|
bool *pressed,
|
||||||
|
float *velocity
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buttons) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (button_id >= buttons->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Button &button = (*buttons)[button_id];
|
||||||
|
if (pressed) {
|
||||||
|
*pressed = (GameAPI::Buttons::getState(RI_MGR, button) == GameAPI::Buttons::BUTTON_PRESSED);
|
||||||
|
}
|
||||||
|
if (velocity) {
|
||||||
|
*velocity = GameAPI::Buttons::getVelocity(RI_MGR, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_set_button (
|
||||||
|
uint32_t button_id,
|
||||||
|
bool pressed,
|
||||||
|
float velocity
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buttons) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (button_id >= buttons->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
if (pressed) {
|
||||||
|
velocity = std::clamp(velocity, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Button &button = (*buttons)[button_id];
|
||||||
|
if (pressed) {
|
||||||
|
button.override_state = pressed ? GameAPI::Buttons::BUTTON_PRESSED : GameAPI::Buttons::BUTTON_NOT_PRESSED;
|
||||||
|
button.override_velocity = velocity;
|
||||||
|
}
|
||||||
|
button.override_enabled = pressed;
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_get_analog (
|
||||||
|
uint32_t analog_id,
|
||||||
|
float *value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!analogs) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (analog_id >= analogs->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
if (!value) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Analog &analog = (*analogs)[analog_id];
|
||||||
|
*value = GameAPI::Analogs::getState(RI_MGR, analog);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_set_analog (
|
||||||
|
uint32_t analog_id,
|
||||||
|
bool override_active,
|
||||||
|
float value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!analogs) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (analog_id >= analogs->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
if (override_active) {
|
||||||
|
value = std::clamp(value, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Analog &analog = (*analogs)[analog_id];
|
||||||
|
if (override_active) {
|
||||||
|
analog.override_state = value;
|
||||||
|
}
|
||||||
|
analog.override_enabled = override_active;
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_get_light(
|
||||||
|
uint32_t light_id,
|
||||||
|
float *value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lights) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (light_id >= lights->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
if (!value) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
Light &light = (*lights)[light_id];
|
||||||
|
*value = GameAPI::Lights::readLight(RI_MGR, light);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_set_light(
|
||||||
|
uint32_t light_id,
|
||||||
|
bool override_active,
|
||||||
|
float value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lights) {
|
||||||
|
return SPICE_SDK_STATUS_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (light_id >= lights->size()) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
if (override_active) {
|
||||||
|
value = std::clamp(value, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Light &light = (*lights)[light_id];
|
||||||
|
if (override_active) {
|
||||||
|
light.override_state = value;
|
||||||
|
}
|
||||||
|
light.override_enabled = override_active;
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_set_touch(
|
||||||
|
const SPICE_SDK_TOUCH_POINT *points,
|
||||||
|
uint32_t count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0 || !points) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TouchPoint> touch_points;
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
const SPICE_SDK_TOUCH_POINT &point = points[i];
|
||||||
|
touch_points.emplace_back(TouchPoint {
|
||||||
|
.id = point.id,
|
||||||
|
.x = point.x,
|
||||||
|
.y = point.y,
|
||||||
|
.mouse = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
touch_write_points(&touch_points);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_clear_touch(
|
||||||
|
const uint32_t *ids,
|
||||||
|
uint32_t count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0 || !ids) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DWORD> touch_point_ids;
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
touch_point_ids.push_back(ids[i]);
|
||||||
|
}
|
||||||
|
touch_remove_points(&touch_point_ids);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_insert_card(
|
||||||
|
uint8_t unit,
|
||||||
|
const char *card_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit >= 2) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!card_id) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
if (strlen(card_id) != 16) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to binary
|
||||||
|
uint8_t card_bin[8] {};
|
||||||
|
if (!hex2bin(card_id, card_bin)) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert
|
||||||
|
eamuse_card_insert(unit & 1, card_bin);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KeypadMapping {
|
||||||
|
char character;
|
||||||
|
uint16_t state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static KeypadMapping KEYPAD_MAPPINGS[] = {
|
||||||
|
{ '0', 1 << EAM_IO_KEYPAD_0 },
|
||||||
|
{ '1', 1 << EAM_IO_KEYPAD_1 },
|
||||||
|
{ '2', 1 << EAM_IO_KEYPAD_2 },
|
||||||
|
{ '3', 1 << EAM_IO_KEYPAD_3 },
|
||||||
|
{ '4', 1 << EAM_IO_KEYPAD_4 },
|
||||||
|
{ '5', 1 << EAM_IO_KEYPAD_5 },
|
||||||
|
{ '6', 1 << EAM_IO_KEYPAD_6 },
|
||||||
|
{ '7', 1 << EAM_IO_KEYPAD_7 },
|
||||||
|
{ '8', 1 << EAM_IO_KEYPAD_8 },
|
||||||
|
{ '9', 1 << EAM_IO_KEYPAD_9 },
|
||||||
|
{ 'A', 1 << EAM_IO_KEYPAD_00 },
|
||||||
|
{ 'D', 1 << EAM_IO_KEYPAD_DECIMAL },
|
||||||
|
};
|
||||||
|
|
||||||
|
SPICE_SDK_STATUS_CODE
|
||||||
|
__cdecl
|
||||||
|
sdk_set_keypad(
|
||||||
|
uint8_t unit,
|
||||||
|
char key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::shared_lock lock(sdk_global_mutex);
|
||||||
|
if (!sdk_initialized) {
|
||||||
|
return SPICE_SDK_STATUS_TOO_LATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unit >= 2) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == 0) {
|
||||||
|
eamuse_set_keypad_overrides(unit, 0);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find mapping
|
||||||
|
uint16_t state = 0;
|
||||||
|
bool mapping_found = false;
|
||||||
|
for (auto &mapping : KEYPAD_MAPPINGS) {
|
||||||
|
if (mapping.character == key) {
|
||||||
|
state |= mapping.state;
|
||||||
|
mapping_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for error
|
||||||
|
if (!mapping_found) {
|
||||||
|
return SPICE_SDK_STATUS_INVALID_ARGUMENT_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set
|
||||||
|
eamuse_set_keypad_overrides(unit, state);
|
||||||
|
return SPICE_SDK_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace sdk
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace sdk {
|
||||||
|
|
||||||
|
void register_sdk_hooks(std::string dll, HINSTANCE module);
|
||||||
|
void init_sdk_modules();
|
||||||
|
void fini_sdk_modules();
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user