mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
api: allow lights.read() to be filtered by light names (#271)
## 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.
This commit is contained in:
@@ -181,6 +181,12 @@ All of those three modules have equally named methods for you to call.
|
|||||||
- removes the override value from the objects specified by name
|
- removes the override value from the objects specified by name
|
||||||
- if no names were passed, all overrides will be removed
|
- if no names were passed, all overrides will be removed
|
||||||
|
|
||||||
|
##### Additional API for lights
|
||||||
|
- read(name: string, ...)
|
||||||
|
- same as read(), but you can specify light names
|
||||||
|
- write_reset(name: str, ...)
|
||||||
|
- same as write_reset(), but it accepts a flat list of strings
|
||||||
|
|
||||||
#### Touch
|
#### Touch
|
||||||
- read()
|
- read()
|
||||||
- returns an array of state objects containing id, x and y
|
- returns an array of state objects containing id, x and y
|
||||||
@@ -252,6 +258,12 @@ which also means that your hex edits are applicable directly.
|
|||||||
- image_resize_set_scene(scene: int)
|
- image_resize_set_scene(scene: int)
|
||||||
- sets the active scene for image resize state; set to 0 to disable resize
|
- sets the active scene for image resize state; set to 0 to disable resize
|
||||||
|
|
||||||
|
## Native wrapper libraries
|
||||||
|
Spicetools provides wrapper libraries in: Arduino, C++, Dart, and Python.
|
||||||
|
Python is the only one that is fully spec compliant.
|
||||||
|
Other libraries may be missing features and contain bugs; please feel free to
|
||||||
|
contribute code to fill the gaps if you work on a project using these libraries.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Unless otherwise noted, all files are licensed under the GPLv3.
|
Unless otherwise noted, all files are licensed under the GPLv3.
|
||||||
See the LICENSE file for the full license text.
|
See the LICENSE file for the full license text.
|
||||||
|
|||||||
@@ -19,11 +19,16 @@ namespace api::modules {
|
|||||||
functions["read"] = std::bind(&Lights::read, this, _1, _2);
|
functions["read"] = std::bind(&Lights::read, this, _1, _2);
|
||||||
functions["write"] = std::bind(&Lights::write, this, _1, _2);
|
functions["write"] = std::bind(&Lights::write, this, _1, _2);
|
||||||
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
|
functions["write_reset"] = std::bind(&Lights::write_reset, this, _1, _2);
|
||||||
lights = games::get_lights(eamuse_get_game());
|
|
||||||
|
this->lights = games::get_lights(eamuse_get_game());
|
||||||
|
for (auto &light : *this->lights) {
|
||||||
|
this->lights_by_names.emplace(light.getName(), light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read()
|
* read()
|
||||||
|
* read(name: str, ...)
|
||||||
*/
|
*/
|
||||||
void Lights::read(api::Request &req, Response &res) {
|
void Lights::read(api::Request &req, Response &res) {
|
||||||
|
|
||||||
@@ -32,17 +37,39 @@ namespace api::modules {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add state for each light
|
// all lights for this game
|
||||||
for (auto &light : *this->lights) {
|
if (req.params.Size() == 0) {
|
||||||
Value state(kArrayType);
|
// add state for each light
|
||||||
Value light_name(light.getName().c_str(), res.doc()->GetAllocator());
|
for (auto &light : *this->lights) {
|
||||||
Value light_state(GameAPI::Lights::readLight(RI_MGR, light));
|
get_light(light, res);
|
||||||
Value light_enabled(light.override_enabled);
|
}
|
||||||
state.PushBack(light_name, res.doc()->GetAllocator());
|
|
||||||
state.PushBack(light_state, res.doc()->GetAllocator());
|
return;
|
||||||
state.PushBack(light_enabled, res.doc()->GetAllocator());
|
|
||||||
res.add_data(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,6 +117,7 @@ namespace api::modules {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* write_reset()
|
* write_reset()
|
||||||
|
* write_reset(name: str, ...)
|
||||||
* write_reset([name: str], ...)
|
* write_reset([name: str], ...)
|
||||||
*/
|
*/
|
||||||
void Lights::write_reset(Request &req, Response &res) {
|
void Lights::write_reset(Request &req, Response &res) {
|
||||||
@@ -119,26 +147,28 @@ namespace api::modules {
|
|||||||
|
|
||||||
// loop parameters
|
// loop parameters
|
||||||
for (Value ¶m : req.params.GetArray()) {
|
for (Value ¶m : req.params.GetArray()) {
|
||||||
|
const char* light_name = nullptr;
|
||||||
|
|
||||||
// check params
|
// check params
|
||||||
if (!param.IsArray()) {
|
if (param.IsArray()) {
|
||||||
error(res, "parameters must be arrays");
|
if (param.Size() < 1) {
|
||||||
return;
|
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");
|
||||||
}
|
}
|
||||||
if (param.Size() < 1) {
|
|
||||||
error_params_insufficient(res);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!param[0].IsString()) {
|
|
||||||
error_type(res, "name", "string");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get params
|
|
||||||
auto light_name = param[0].GetString();
|
|
||||||
|
|
||||||
// write analog state
|
// write analog state
|
||||||
if (!this->write_light_reset(light_name)) {
|
if (light_name && !this->write_light_reset(light_name)) {
|
||||||
error_unknown(res, "analog", light_name);
|
error_unknown(res, "analog", light_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -153,21 +183,20 @@ namespace api::modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find light
|
// find light
|
||||||
for (auto &light : *this->lights) {
|
if (this->lights_by_names.contains(name)) {
|
||||||
if (light.getName() == name) {
|
auto &light = this->lights_by_names.at(name).get();
|
||||||
light.override_state = CLAMP(state, 0.f, 1.f);
|
light.override_state = CLAMP(state, 0.f, 1.f);
|
||||||
light.override_enabled = true;
|
light.override_enabled = true;
|
||||||
|
|
||||||
if (cfg::CONFIGURATOR_STANDALONE) {
|
if (cfg::CONFIGURATOR_STANDALONE) {
|
||||||
GameAPI::Lights::writeLight(RI_MGR, light, state);
|
GameAPI::Lights::writeLight(RI_MGR, light, state);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// unknown light
|
return true;
|
||||||
return false;
|
} else {
|
||||||
|
// unknown light
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lights::write_light_reset(std::string name) {
|
bool Lights::write_light_reset(std::string name) {
|
||||||
@@ -178,14 +207,13 @@ namespace api::modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find light
|
// find light
|
||||||
for (auto &light : *this->lights) {
|
if (this->lights_by_names.contains(name)) {
|
||||||
if (light.getName() == name) {
|
auto &light = this->lights_by_names.at(name).get();
|
||||||
light.override_enabled = false;
|
light.override_enabled = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
|
// unknown light
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unknown light
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <external/robin_hood.h>
|
||||||
|
|
||||||
#include "api/module.h"
|
#include "api/module.h"
|
||||||
#include "api/request.h"
|
#include "api/request.h"
|
||||||
#include "cfg/api.h"
|
#include "cfg/api.h"
|
||||||
@@ -15,6 +17,7 @@ namespace api::modules {
|
|||||||
|
|
||||||
// state
|
// state
|
||||||
std::vector<Light> *lights;
|
std::vector<Light> *lights;
|
||||||
|
robin_hood::unordered_map<std::string, std::reference_wrapper<Light>> lights_by_names;
|
||||||
|
|
||||||
// function definitions
|
// function definitions
|
||||||
void read(Request &req, Response &res);
|
void read(Request &req, Response &res);
|
||||||
@@ -22,6 +25,7 @@ namespace api::modules {
|
|||||||
void write_reset(Request &req, Response &res);
|
void write_reset(Request &req, Response &res);
|
||||||
|
|
||||||
// helper
|
// helper
|
||||||
|
void get_light(Light &light, Response &res);
|
||||||
bool write_light(std::string name, float state);
|
bool write_light(std::string name, float state);
|
||||||
bool write_light_reset(std::string name);
|
bool write_light_reset(std::string name);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,8 +2,14 @@ from .connection import Connection
|
|||||||
from .request import Request
|
from .request import Request
|
||||||
|
|
||||||
|
|
||||||
def lights_read(con: Connection):
|
def lights_read(con: Connection, light_names=None):
|
||||||
res = con.request(Request("lights", "read"))
|
req = Request("lights", "read")
|
||||||
|
|
||||||
|
if light_names:
|
||||||
|
for light_name in light_names:
|
||||||
|
req.add_param(light_name)
|
||||||
|
|
||||||
|
res = con.request(req)
|
||||||
return res.get_data()
|
return res.get_data()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user