Files
spice2x-r3d/src/spice2x/launcher/shutdown.cpp
T
bicarusandGitHub 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

125 lines
2.9 KiB
C++

// included early to avoid warning
#include <winsock2.h>
#include "shutdown.h"
#include "api/controller.h"
#include "easrv/easrv.h"
#include "rawinput/rawinput.h"
#include "hooks/audio/audio.h"
#include "hooks/graphics/graphics.h"
#include "util/deferlog.h"
#include "util/logging.h"
#include "launcher.h"
#include "logger.h"
#include "nvapi/nvapi.h"
#include "sdk/sdk.h"
namespace launcher {
void stop_subsystems() {
// note that it is possible for stop_subsystems to be called multiple times
// (e.g., crashing, and then closing the window)
// therefore, subsystems need to be guarded against multiple unload attempts
log_info("launcher", "stopping subsystems");
sdk::fini_sdk_modules();
// reset monitor settings
reset_monitor_on_exit();
// before shutting down logger, dump any deferred log messages
deferredlogs::dump_to_logger();
// flush/stop logger
logger::stop();
// stop ea server
easrv_shutdown();
// free api sockets
if (API_CONTROLLER) {
API_CONTROLLER->free_socket();
}
// notify audio hook
hooks::audio::stop();
// stop raw input
if (RI_MGR) {
RI_MGR->stop();
}
// unload nvapi and free library (if loaded)
nvapi::unload();
}
void kill(UINT exit_code) {
// terminate
TerminateProcess(GetCurrentProcess(), exit_code);
}
void shutdown(UINT exit_code) {
// force exit after 1s
std::thread force_thread([exit_code] {
Sleep(1000);
log_info("launcher", "force shutdown");
kill(exit_code);
return nullptr;
});
force_thread.detach();
// stop all subsystems
stop_subsystems();
// terminate
kill(exit_code);
}
static void restart_spawn() {
// never do this twice
static bool already_done = false;
if (already_done) {
return;
} else {
already_done = true;
}
// start the process using the same args
if (LAUNCHER_ARGC > 0) {
// build cmd line
std::string cmd_line = "START \"\" ";
for (int i = 0; i < LAUNCHER_ARGC; i++)
cmd_line += " \"" + std::string(LAUNCHER_ARGV[i]) + "\"";
// run command
system(cmd_line.c_str());
}
}
void restart() {
// force restart after 1s
std::thread force_thread([] {
Sleep(1000);
log_info("launcher", "force restart");
restart_spawn();
launcher::kill(0);
return nullptr;
});
force_thread.detach();
// clean up before restart so resources can be reclaimed
stop_subsystems();
// spawn new and terminate this process
restart_spawn();
launcher::kill(0);
}
}