diff --git a/src/spice2x/README.md b/src/spice2x/README.md index 979ae65..e7c754d 100644 --- a/src/spice2x/README.md +++ b/src/spice2x/README.md @@ -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 - 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 - read() - 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) - 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 Unless otherwise noted, all files are licensed under the GPLv3. See the LICENSE file for the full license text. diff --git a/src/spice2x/api/modules/lights.cpp b/src/spice2x/api/modules/lights.cpp index 2e3dc15..749b0af 100644 --- a/src/spice2x/api/modules/lights.cpp +++ b/src/spice2x/api/modules/lights.cpp @@ -19,11 +19,16 @@ namespace api::modules { 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); - 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(name: str, ...) */ void Lights::read(api::Request &req, Response &res) { @@ -32,17 +37,39 @@ namespace api::modules { return; } - // add state for each light - for (auto &light : *this->lights) { - 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); + // 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); } /** @@ -90,6 +117,7 @@ namespace api::modules { /** * write_reset() + * write_reset(name: str, ...) * write_reset([name: str], ...) */ void Lights::write_reset(Request &req, Response &res) { @@ -119,26 +147,28 @@ namespace api::modules { // loop parameters for (Value ¶m : req.params.GetArray()) { + const char* light_name = nullptr; // check params - if (!param.IsArray()) { - error(res, "parameters must be arrays"); - return; + 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"); } - 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 - if (!this->write_light_reset(light_name)) { + if (light_name && !this->write_light_reset(light_name)) { error_unknown(res, "analog", light_name); continue; } @@ -153,21 +183,20 @@ namespace api::modules { } // find light - for (auto &light : *this->lights) { - if (light.getName() == name) { - light.override_state = CLAMP(state, 0.f, 1.f); - light.override_enabled = true; + 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; + if (cfg::CONFIGURATOR_STANDALONE) { + GameAPI::Lights::writeLight(RI_MGR, light, state); } - } - // unknown light - return false; + return true; + } else { + // unknown light + return false; + } } bool Lights::write_light_reset(std::string name) { @@ -178,14 +207,13 @@ namespace api::modules { } // find light - for (auto &light : *this->lights) { - if (light.getName() == name) { - light.override_enabled = false; - return true; - } + 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; } - - // unknown light - return false; } } diff --git a/src/spice2x/api/modules/lights.h b/src/spice2x/api/modules/lights.h index b174210..b020f35 100644 --- a/src/spice2x/api/modules/lights.h +++ b/src/spice2x/api/modules/lights.h @@ -1,6 +1,8 @@ #pragma once #include +#include + #include "api/module.h" #include "api/request.h" #include "cfg/api.h" @@ -15,6 +17,7 @@ namespace api::modules { // state std::vector *lights; + robin_hood::unordered_map> lights_by_names; // function definitions void read(Request &req, Response &res); @@ -22,6 +25,7 @@ namespace api::modules { void write_reset(Request &req, Response &res); // helper + void get_light(Light &light, Response &res); bool write_light(std::string name, float state); bool write_light_reset(std::string name); }; diff --git a/src/spice2x/api/resources/python/spiceapi/lights.py b/src/spice2x/api/resources/python/spiceapi/lights.py index 038373d..dba33f3 100644 --- a/src/spice2x/api/resources/python/spiceapi/lights.py +++ b/src/spice2x/api/resources/python/spiceapi/lights.py @@ -2,8 +2,14 @@ from .connection import Connection from .request import Request -def lights_read(con: Connection): - res = con.request(Request("lights", "read")) +def lights_read(con: Connection, light_names=None): + 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()