Files
spice2x.github.io/src/spice2x/sdk/sample/v0/cpp/v0_cpp.cpp
T
bicarus cd0ba51b5a 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.
2026-05-06 23:29:52 -07:00

58 lines
1.3 KiB
C++

#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();
}
}