mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-09-28 09:48:17 +03:00
## Link to GitHub Issue or related Pull Request, if one exists developer request ## Description of change Expose coin insert API over the SDK ## Testing see sample sdk code
133 lines
4.1 KiB
C++
133 lines
4.1 KiB
C++
#include <format>
|
|
#include <chrono>
|
|
#include <thread>
|
|
#include <windows.h>
|
|
|
|
#include "sdk/include/spicesdk.h"
|
|
#include "sdk/include/spicesdk_io.h"
|
|
|
|
// this sample assumes that the game is DDR
|
|
|
|
// convenience wrapper for logging; feel free to add other levels
|
|
#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);
|
|
|
|
// main entry point into the DLL
|
|
// spice executable will call into this shortly after the game is partially
|
|
// initialized (but not quite fully booted just yet)
|
|
SPICE_SDK_ENTRY_POINT
|
|
spice_sdk_entry_point(
|
|
spice_sdk_init_func *init
|
|
)
|
|
{
|
|
SPICE_SDK_STATUS_CODE status;
|
|
|
|
// SPICE_SDK_V0 must be zeroed AND the size field must be set
|
|
spice.size = sizeof(spice);
|
|
|
|
// initialize the SDK - can be called any time, but we'll do it here
|
|
status = init(0, destroy_callback, &spice);
|
|
|
|
// always check for return value; failure could be usage error,
|
|
// or the spice executable doesn't support this SDK version
|
|
// check the log messages from sdk:
|
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
LOG_INFO("plugin loaded");
|
|
|
|
// spin up a worker thread
|
|
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();
|
|
}
|
|
}
|
|
|
|
struct ArrowButton {
|
|
int key;
|
|
SPICE_SDK_DDR_BUTTONS button;
|
|
const char* name;
|
|
bool previous_state;
|
|
};
|
|
|
|
static ArrowButton arrow_buttons[] = {
|
|
{ VK_UP, DDR_Button_P1_PANEL_UP, "UP", false },
|
|
{ VK_DOWN, DDR_Button_P1_PANEL_DOWN, "DOWN", false },
|
|
{ VK_LEFT, DDR_Button_P1_PANEL_LEFT, "LEFT", false },
|
|
{ VK_RIGHT, DDR_Button_P1_PANEL_RIGHT, "RIGHT", false },
|
|
};
|
|
|
|
// worker thread for I/O
|
|
static void worker_thread_main(std::stop_token stop_token) {
|
|
bool coin_previous_state[10] = {};
|
|
while (!stop_token.stop_requested()) {
|
|
|
|
// insert coin
|
|
const bool control_pressed = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
|
|
for (uint8_t amount = 0; amount < 10; amount++) {
|
|
const bool coin_pressed = control_pressed &&
|
|
((GetAsyncKeyState('0' + amount) & 0x8000) != 0);
|
|
|
|
if (coin_pressed && !coin_previous_state[amount] && spice.insert_coin) {
|
|
const auto status = spice.insert_coin(amount);
|
|
if (status != SPICE_SDK_STATUS_SUCCESS) {
|
|
LOG_INFO(std::format(
|
|
"coin insertion failed: {}",
|
|
static_cast<int>(status)).c_str());
|
|
} else {
|
|
const auto message = std::format(
|
|
"v0_cpp: inserted {} coin{}", amount, amount == 1 ? "" : "s");
|
|
LOG_INFO(message.c_str());
|
|
if (spice.add_toast) {
|
|
spice.add_toast(SPICE_SDK_TOAST_LEVEL_SUCCESS, message.c_str());
|
|
}
|
|
}
|
|
}
|
|
coin_previous_state[amount] = coin_pressed;
|
|
}
|
|
|
|
// check for ctrl + arrow keys and trigger p1 pad arrows
|
|
for (auto& arrow : arrow_buttons) {
|
|
if (((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0) &&
|
|
((GetAsyncKeyState(arrow.key) & 0x8000) != 0)) {
|
|
spice.set_button(arrow.button, true, 1.f);
|
|
|
|
if (!arrow.previous_state) {
|
|
|
|
if (spice.add_toast) {
|
|
spice.add_toast(
|
|
SPICE_SDK_TOAST_LEVEL_INFO,
|
|
std::format("v0_cpp: let me hear you say: {}", arrow.name).c_str());
|
|
} else {
|
|
LOG_INFO(std::format("let me hear you say: {}", arrow.name).c_str());
|
|
}
|
|
|
|
arrow.previous_state = true;
|
|
}
|
|
} else {
|
|
spice.set_button(arrow.button, false, 0.f);
|
|
arrow.previous_state = false;
|
|
}
|
|
}
|
|
|
|
Sleep(1);
|
|
}
|
|
}
|