mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-10-02 08:18:14 -07:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50b38b856f | |||
| dad88caf01 |
@@ -144,6 +144,13 @@ restriction is that the ID has to be a valid 64-bit unsigned integer.
|
||||
`busy`
|
||||
|
||||
#### Card
|
||||
- get_cards()
|
||||
- returns the current card ID and source for each active card reader
|
||||
- each entry contains `index`, `card_id`, and `source`
|
||||
- `source` is `file` or `override`
|
||||
- file entries also contain `file_name`, without the full configured path
|
||||
- `-card0` and `-card1` overrides do not contain `file_name`
|
||||
- this function only works when an API password is configured
|
||||
- insert(index: uint, card_id: hex)
|
||||
- inserts a card which gets read by the emulated card readers for the game
|
||||
- index has to be either 0 (for P1) or 1 (for P2)
|
||||
|
||||
@@ -337,9 +337,11 @@ bool Controller::process_request(ClientState *state, const char *in, size_t in_s
|
||||
if (module->name == request.module) {
|
||||
module_found = true;
|
||||
|
||||
// check password force
|
||||
if (module->password_force && this->password.empty() && request.function != "session_refresh") {
|
||||
Value err("Module requires the password to be set.");
|
||||
// check password requirement
|
||||
if (module->requires_password(request.function)
|
||||
&& this->password.empty()
|
||||
&& request.function != "session_refresh") {
|
||||
Value err("Function requires the password to be set.");
|
||||
response.add_error(err);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@ namespace api {
|
||||
this->password_force = password_force;
|
||||
}
|
||||
|
||||
void Module::require_password(const std::string &function) {
|
||||
this->password_force_functions.emplace(function);
|
||||
}
|
||||
|
||||
bool Module::requires_password(const std::string &function) const {
|
||||
return this->password_force || this->password_force_functions.contains(function);
|
||||
}
|
||||
|
||||
void Module::handle(Request &req, Response &res) {
|
||||
|
||||
// log module access
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <external/robin_hood.h>
|
||||
|
||||
#include "response.h"
|
||||
@@ -26,6 +27,13 @@ namespace api {
|
||||
// default constructor
|
||||
explicit Module(std::string name, bool password_force=false);
|
||||
|
||||
void require_password(const std::string &function);
|
||||
|
||||
private:
|
||||
|
||||
// functions which expose sensitive data or actions
|
||||
std::unordered_set<std::string> password_force_functions;
|
||||
|
||||
public:
|
||||
|
||||
// virtual deconstructor
|
||||
@@ -35,6 +43,8 @@ namespace api {
|
||||
std::string name;
|
||||
bool password_force;
|
||||
|
||||
bool requires_password(const std::string &function) const;
|
||||
|
||||
// the magic
|
||||
void handle(Request &req, Response &res);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "card.h"
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "util/logging.h"
|
||||
@@ -11,8 +12,71 @@ using namespace rapidjson;
|
||||
|
||||
namespace api::modules {
|
||||
|
||||
static bool normalize_card_id(const std::string &value, std::string &card_id) {
|
||||
if (value.size() != 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t card_bin[8] {};
|
||||
if (!hex2bin(value.c_str(), card_bin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
card_id = bin2hex(card_bin, std::size(card_bin));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_card_id(const std::filesystem::path &path, std::string &card_id) {
|
||||
std::ifstream file(path);
|
||||
char buffer[16] {};
|
||||
if (!file.read(buffer, std::size(buffer))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return normalize_card_id(std::string(buffer, std::size(buffer)), card_id);
|
||||
}
|
||||
|
||||
Card::Card() : Module("card") {
|
||||
functions["get_cards"] = std::bind(&Card::get_cards, this, _1, _2);
|
||||
functions["insert"] = std::bind(&Card::insert, this, _1, _2);
|
||||
require_password("get_cards");
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cards()
|
||||
*/
|
||||
void Card::get_cards(Request &req, Response &res) {
|
||||
auto &alloc = res.doc()->GetAllocator();
|
||||
|
||||
for (int index = 0; index < eamuse_get_game_keypads(); index++) {
|
||||
std::string card_id;
|
||||
std::string filename;
|
||||
const auto card_override = eamuse_get_card_override(index);
|
||||
const bool has_override = !card_override.empty();
|
||||
|
||||
if (has_override) {
|
||||
if (!normalize_card_id(card_override, card_id)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
const auto path = eamuse_get_card_path(index);
|
||||
if (!read_card_id(path, card_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto filename_u8 = path.filename().u8string();
|
||||
filename.assign(filename_u8.begin(), filename_u8.end());
|
||||
}
|
||||
|
||||
Value card(kObjectType);
|
||||
card.AddMember("index", index, alloc);
|
||||
card.AddMember("card_id", Value(card_id.c_str(), alloc), alloc);
|
||||
card.AddMember("source", Value(has_override ? "override" : "file", alloc), alloc);
|
||||
if (!has_override) {
|
||||
card.AddMember("file_name", Value(filename.c_str(), alloc), alloc);
|
||||
}
|
||||
res.add_data(card);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace api::modules {
|
||||
private:
|
||||
|
||||
// function definitions
|
||||
void get_cards(Request &req, Response &res);
|
||||
void insert(Request &req, Response &res);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
part of spiceapi;
|
||||
|
||||
class CardInfo {
|
||||
final int index;
|
||||
final String cardID;
|
||||
final String source;
|
||||
final String? fileName;
|
||||
|
||||
CardInfo(this.index, this.cardID, this.source, this.fileName);
|
||||
}
|
||||
|
||||
Future<List<CardInfo>> cardGetCards(Connection con) {
|
||||
var req = Request("card", "get_cards");
|
||||
return con.request(req).then((res) {
|
||||
List<CardInfo> cards = [];
|
||||
for (var value in res.getData()) {
|
||||
cards.add(
|
||||
CardInfo(
|
||||
value["index"],
|
||||
value["card_id"],
|
||||
value["source"],
|
||||
value["file_name"],
|
||||
),
|
||||
);
|
||||
}
|
||||
return cards;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> cardInsert(Connection con, int unit, String cardID) {
|
||||
var req = Request("card", "insert");
|
||||
req.addParam(unit);
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
part of spiceapi;
|
||||
|
||||
class CardInfo {
|
||||
final int index;
|
||||
final String cardID;
|
||||
final String source;
|
||||
final String? fileName;
|
||||
|
||||
CardInfo(this.index, this.cardID, this.source, this.fileName);
|
||||
}
|
||||
|
||||
Future<List<CardInfo>> cardGetCards(Connection con) {
|
||||
var req = Request("card", "get_cards");
|
||||
return con.request(req).then((res) {
|
||||
List<CardInfo> cards = [];
|
||||
for (var value in res.getData()) {
|
||||
cards.add(
|
||||
CardInfo(
|
||||
value["index"],
|
||||
value["card_id"],
|
||||
value["source"],
|
||||
value["file_name"],
|
||||
),
|
||||
);
|
||||
}
|
||||
return cards;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> cardInsert(Connection con, int unit, String cardID) {
|
||||
var req = Request("card", "insert");
|
||||
req.addParam(unit);
|
||||
|
||||
@@ -2,6 +2,10 @@ from .connection import Connection
|
||||
from .request import Request
|
||||
|
||||
|
||||
def card_get_cards(con: Connection):
|
||||
return con.request(Request("card", "get_cards")).get_data()
|
||||
|
||||
|
||||
def card_insert(con: Connection, unit: int, card_id: str):
|
||||
req = Request("card", "insert")
|
||||
req.add_param(unit)
|
||||
|
||||
@@ -285,8 +285,10 @@ static int __cdecl device_read_secplug(int a1, int a2, int a3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __cdecl device_set_coinblocker_open(char number, char open) {
|
||||
return 0;
|
||||
static void __cdecl device_set_coinblocker_open(char slot1_open, char slot2_open) {
|
||||
// libdevice exposes one open flag per coin slot. Since spice has a shared
|
||||
// software coin stock, consider it blocked only when both slots are closed.
|
||||
eamuse_coin_set_block(!slot1_open && !slot2_open);
|
||||
}
|
||||
|
||||
static void __cdecl device_set_coincounter_merge() {
|
||||
@@ -617,7 +619,9 @@ void spicedevice_attach() {
|
||||
detour::inline_hook((void *) device_finalize, libutils::try_proc_list(
|
||||
DEVICE_INSTANCE, {"device_finalize", "?device_finalize@@YAXXZ"}));
|
||||
detour::inline_hook((void *) device_get_coinstock, libutils::try_proc_list(
|
||||
DEVICE_INSTANCE, {"device_get_coinstock", "?device_get_coinstock@@YAXPEAG0@Z"}));
|
||||
DEVICE_INSTANCE, {"device_get_coinstock",
|
||||
"?device_get_coinstock@@YAXPEAG0@Z",
|
||||
"?device_get_coinstock@@YAXPAG0@Z"}));
|
||||
detour::inline_hook((void *) device_get_coinstock_all, libutils::try_proc_list(
|
||||
DEVICE_INSTANCE, {"device_get_coinstock_all",
|
||||
"?device_get_coinstock_all@@YAXPEAG0@Z",
|
||||
|
||||
+26
-14
@@ -34,6 +34,7 @@ static uint16_t KEYPAD_STATE_OVERRIDES_READER[] = {0, 0};
|
||||
static uint16_t KEYPAD_STATE_OVERRIDES_OVERLAY[] = {0, 0};
|
||||
static std::string EAMUSE_GAME_NAME;
|
||||
static ConfigKeypadBindings KEYPAD_BINDINGS {};
|
||||
static std::mutex KEYPAD_BINDINGS_LOCK;
|
||||
|
||||
// auto card
|
||||
bool AUTO_INSERT_CARD[2] = {false, false};
|
||||
@@ -87,23 +88,23 @@ bool eamuse_get_card(int active_count, int unit_id, uint8_t *card) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// get file path
|
||||
std::filesystem::path path;
|
||||
if (!KEYPAD_BINDINGS.card_paths[index].empty()) {
|
||||
path = KEYPAD_BINDINGS.card_paths[index];
|
||||
} else {
|
||||
path = index > 0 ? "card1.txt" : "card0.txt";
|
||||
}
|
||||
|
||||
// call the next function
|
||||
return eamuse_get_card(path, card, index);
|
||||
return eamuse_get_card(eamuse_get_card_path(index), card, index);
|
||||
}
|
||||
|
||||
std::filesystem::path eamuse_get_card_path(size_t index) {
|
||||
std::lock_guard<std::mutex> lock(KEYPAD_BINDINGS_LOCK);
|
||||
if (index >= std::size(KEYPAD_BINDINGS.card_paths)) {
|
||||
return {};
|
||||
}
|
||||
if (!KEYPAD_BINDINGS.card_paths[index].empty()) {
|
||||
return KEYPAD_BINDINGS.card_paths[index];
|
||||
}
|
||||
return index > 0 ? "card1.txt" : "card0.txt";
|
||||
}
|
||||
|
||||
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index) {
|
||||
// do a quick copy under lock
|
||||
std::unique_lock<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||
const auto card_override = CARD_OVERRIDES[index];
|
||||
lock.unlock();
|
||||
const auto card_override = eamuse_get_card_override(index);
|
||||
|
||||
// Check if card overrides are present
|
||||
if (!card_override.empty()) {
|
||||
@@ -149,6 +150,14 @@ bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index
|
||||
return eamuse_get_card_from_file(path, card, index);
|
||||
}
|
||||
|
||||
std::string eamuse_get_card_override(size_t index) {
|
||||
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||
if (index >= std::size(CARD_OVERRIDES)) {
|
||||
return {};
|
||||
}
|
||||
return CARD_OVERRIDES[index];
|
||||
}
|
||||
|
||||
bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card, int index) {
|
||||
|
||||
// open file
|
||||
@@ -584,6 +593,7 @@ std::string eamuse_get_keypad_state_str(size_t unit) {
|
||||
}
|
||||
|
||||
bool eamuse_keypad_state_naive() {
|
||||
std::lock_guard<std::mutex> lock(KEYPAD_BINDINGS_LOCK);
|
||||
return KEYPAD_BINDINGS.keypads[0].empty() && KEYPAD_BINDINGS.keypads[1].empty();
|
||||
}
|
||||
|
||||
@@ -595,7 +605,9 @@ void eamuse_set_game(std::string game) {
|
||||
}
|
||||
|
||||
void eamuse_update_keypad_bindings() {
|
||||
KEYPAD_BINDINGS = Config::getInstance().getKeypadBindings(EAMUSE_GAME_NAME);
|
||||
auto bindings = Config::getInstance().getKeypadBindings(EAMUSE_GAME_NAME);
|
||||
std::lock_guard<std::mutex> lock(KEYPAD_BINDINGS_LOCK);
|
||||
KEYPAD_BINDINGS = std::move(bindings);
|
||||
}
|
||||
|
||||
const std::string &eamuse_get_game() {
|
||||
|
||||
@@ -43,6 +43,8 @@ extern std::string AUTO_PIN_MACRO_TRIGGER[2];
|
||||
bool eamuse_get_card(int active_count, int unit_id, uint8_t *card);
|
||||
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int unit_id);
|
||||
bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card, int index);
|
||||
std::filesystem::path eamuse_get_card_path(size_t index);
|
||||
std::string eamuse_get_card_override(size_t index);
|
||||
|
||||
void eamuse_card_insert(int unit);
|
||||
void eamuse_card_insert(int unit, const uint8_t *card);
|
||||
|
||||
Reference in New Issue
Block a user