mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
6de122c9f8
## Link to GitHub Issue, if one exists Fixes https://github.com/spice2x/spice2x.github.io/issues/179 ## Description of change Previously, lights.read() did not accept any parameters, instead it returned all lights implemented by the current game. Problem is that this is too large for some embedded implementations; also just inefficient. Add code to accept light names as strings and only return those in the result. For performance, use `robin_hood::unordered_map` to speed up the lookup operation, which was previously a linear search. Add this to Python wrapper library. Did not bother with others. Also, as a bonus - update lights.write_reset() to also accept a flat list of strings, as opposed to array containing a string, which was silly. ## Compiling ➕ ## Testing Tested using spiceremote and writing a short Python program.
220 lines
6.2 KiB
C++
220 lines
6.2 KiB
C++
#include "lights.h"
|
|
#include <functional>
|
|
#include <cfg/configurator.h>
|
|
|
|
#include "external/rapidjson/document.h"
|
|
#include "misc/eamuse.h"
|
|
#include "cfg/light.h"
|
|
#include "launcher/launcher.h"
|
|
#include "games/io.h"
|
|
#include "util/utils.h"
|
|
|
|
using namespace std::placeholders;
|
|
using namespace rapidjson;
|
|
|
|
|
|
namespace api::modules {
|
|
|
|
Lights::Lights() : Module("lights") {
|
|
functions["read"] = std::bind(&Lights::read, this, _1, _2);
|
|
functions["write"] = std::bind(&Lights::write, this, _1, _2);
|
|
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
|
|
|
|
this->lights = games::get_lights(eamuse_get_game());
|
|
for (auto &light : *this->lights) {
|
|
this->lights_by_names.emplace(light.getName(), light);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* read()
|
|
* read(name: str, ...)
|
|
*/
|
|
void Lights::read(api::Request &req, Response &res) {
|
|
|
|
// check light cache
|
|
if (!this->lights) {
|
|
return;
|
|
}
|
|
|
|
// all lights for this game
|
|
if (req.params.Size() == 0) {
|
|
// add state for each light
|
|
for (auto &light : *this->lights) {
|
|
get_light(light, res);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// specified light names
|
|
for (Value ¶m : req.params.GetArray()) {
|
|
// check params
|
|
if (!param.IsString()) {
|
|
error_type(res, "name", "string");
|
|
return;
|
|
}
|
|
const auto name = param.GetString();
|
|
if (this->lights_by_names.contains(name)) {
|
|
get_light(this->lights_by_names.at(name).get(), res);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Lights::get_light(Light &light, Response &res) {
|
|
Value state(kArrayType);
|
|
Value light_name(light.getName().c_str(), res.doc()->GetAllocator());
|
|
Value light_state(GameAPI::Lights::readLight(RI_MGR, light));
|
|
Value light_enabled(light.override_enabled);
|
|
state.PushBack(light_name, res.doc()->GetAllocator());
|
|
state.PushBack(light_state, res.doc()->GetAllocator());
|
|
state.PushBack(light_enabled, res.doc()->GetAllocator());
|
|
res.add_data(state);
|
|
}
|
|
|
|
/**
|
|
* write([name: str, state: float], ...)
|
|
*/
|
|
void Lights::write(Request &req, Response &res) {
|
|
|
|
// check light cache
|
|
if (!this->lights) {
|
|
return;
|
|
}
|
|
|
|
// loop parameters
|
|
for (Value ¶m : req.params.GetArray()) {
|
|
|
|
// check params
|
|
if (!param.IsArray()) {
|
|
error(res, "parameters must be arrays");
|
|
return;
|
|
}
|
|
if (param.Size() < 2) {
|
|
error_params_insufficient(res);
|
|
continue;
|
|
}
|
|
if (!param[0].IsString()) {
|
|
error_type(res, "name", "string");
|
|
continue;
|
|
}
|
|
if (!param[1].IsFloat() && !param[1].IsInt()) {
|
|
error_type(res, "state", "float");
|
|
continue;
|
|
}
|
|
|
|
// get params
|
|
auto light_name = param[0].GetString();
|
|
auto light_state = param[1].GetFloat();
|
|
|
|
// write light state
|
|
if (!this->write_light(light_name, light_state)) {
|
|
error_unknown(res, "light", light_name);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* write_reset()
|
|
* write_reset(name: str, ...)
|
|
* write_reset([name: str], ...)
|
|
*/
|
|
void Lights::write_reset(Request &req, Response &res) {
|
|
|
|
// check light cache
|
|
if (!this->lights) {
|
|
return;
|
|
}
|
|
|
|
// get params
|
|
auto params = req.params.GetArray();
|
|
|
|
// write_reset()
|
|
if (params.Size() == 0) {
|
|
if (lights != nullptr) {
|
|
for (auto &light : *this->lights) {
|
|
if (light.override_enabled) {
|
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
|
GameAPI::Lights::writeLight(RI_MGR, light, light.last_state);
|
|
}
|
|
light.override_enabled = false;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// loop parameters
|
|
for (Value ¶m : req.params.GetArray()) {
|
|
const char* light_name = nullptr;
|
|
|
|
// check params
|
|
if (param.IsArray()) {
|
|
if (param.Size() < 1) {
|
|
error_params_insufficient(res);
|
|
continue;
|
|
}
|
|
if (!param[0].IsString()) {
|
|
error_type(res, "name", "string");
|
|
continue;
|
|
}
|
|
// get params
|
|
light_name = param[0].GetString();
|
|
} else if (param.IsString()) {
|
|
light_name = param.GetString();
|
|
} else {
|
|
error(res, "parameters must be arrays or strings");
|
|
}
|
|
|
|
// write analog state
|
|
if (light_name && !this->write_light_reset(light_name)) {
|
|
error_unknown(res, "analog", light_name);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Lights::write_light(std::string name, float state) {
|
|
|
|
// check light cache
|
|
if (!this->lights) {
|
|
return false;
|
|
}
|
|
|
|
// find light
|
|
if (this->lights_by_names.contains(name)) {
|
|
auto &light = this->lights_by_names.at(name).get();
|
|
light.override_state = CLAMP(state, 0.f, 1.f);
|
|
light.override_enabled = true;
|
|
|
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
|
GameAPI::Lights::writeLight(RI_MGR, light, state);
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
// unknown light
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Lights::write_light_reset(std::string name) {
|
|
|
|
// check light cache
|
|
if (!this->lights) {
|
|
return false;
|
|
}
|
|
|
|
// find light
|
|
if (this->lights_by_names.contains(name)) {
|
|
auto &light = this->lights_by_names.at(name).get();
|
|
light.override_enabled = false;
|
|
return true;
|
|
} else {
|
|
// unknown light
|
|
return false;
|
|
}
|
|
}
|
|
}
|