diff --git a/editor/include/ImGuiCore/ValueInput.hxx b/editor/include/ImGuiCore/ValueInput.hxx index 8db73958..2e716a00 100644 --- a/editor/include/ImGuiCore/ValueInput.hxx +++ b/editor/include/ImGuiCore/ValueInput.hxx @@ -78,6 +78,16 @@ public: for (auto &[name, value]: values) drawInput(value, name); } + void drawInput(pivot::ecs::data::ScriptEntity &entity, const std::string &) + { + for (auto &[name, value]: entity.components) drawInput(value, name); + } + + void drawInput(pivot::ecs::data::List &list, const std::string &name) + { + for (size_t i = 0; i < list.items.size(); i++) drawInput(list.items.at(i), std::to_string(i)); + } + void drawInput(pivot::ecs::data::Value &value, const std::string &name) { std::visit([&name, this](auto &&arg) { this->drawInput(arg, name); }, diff --git a/libecs/include/pivot/ecs/Core/Data/type.hxx b/libecs/include/pivot/ecs/Core/Data/type.hxx index 28672329..60eb9c93 100644 --- a/libecs/include/pivot/ecs/Core/Data/type.hxx +++ b/libecs/include/pivot/ecs/Core/Data/type.hxx @@ -45,6 +45,12 @@ enum class BasicType { /// The property is a reference to another entity EntityRef, + /// The property is of type ScriptEntity + ScriptEntity, + + /// The property is of type List + List, + /// The property is of type Color Color, }; @@ -77,6 +83,9 @@ std::ostream &operator<<(std::ostream &stream, const BasicType &type); std::ostream &operator<<(std::ostream &stream, const RecordType &type); std::ostream &operator<<(std::ostream &stream, const Type &type); +struct ScriptEntity; +struct List; + template constexpr std::optional basic_type_representation = std::nullopt; @@ -100,6 +109,10 @@ template <> constexpr std::optional basic_type_representation = BasicType::Void; template <> constexpr std::optional basic_type_representation = BasicType::EntityRef; +template <> +constexpr std::optional basic_type_representation = BasicType::ScriptEntity; +template <> +constexpr std::optional basic_type_representation = BasicType::List; } // namespace pivot::ecs::data diff --git a/libecs/include/pivot/ecs/Core/Data/value.hxx b/libecs/include/pivot/ecs/Core/Data/value.hxx index 7efa535f..4630ba1b 100644 --- a/libecs/include/pivot/ecs/Core/Data/value.hxx +++ b/libecs/include/pivot/ecs/Core/Data/value.hxx @@ -23,6 +23,31 @@ struct Record : public std::map { RecordType type() const; }; +/// Value containing an entity record and id +struct ScriptEntity { + /// Data::Record of the entities components + data::Record components; + + /// Entity id of the entity + pivot::Entity entityId; + + /// Entity equal Entity + bool operator==(const ScriptEntity &rhs) const { return entityId == rhs.entityId; } + /// Entity comparison + auto operator<=>(const ScriptEntity &rhs) const { return entityId <=> rhs.entityId; } +}; + +/// Value containing a list +struct List { + /// List of values + std::vector items; + + /// List equal List + bool operator==(const List &rhs) const; + /// List comparison + auto operator<=>(const List &rhs) const; +}; + /** \brief A value dynamically typed, which forms the basis of the pivot data model * * A value can be one of those type : @@ -35,8 +60,8 @@ struct Record : public std::map { * - Void (no value) * - Entity (entity reference) */ -struct Value - : public std::variant { +struct Value : public std::variant { using variant::variant; /// Returns the Type corresponding to this Value diff --git a/libecs/source/Core/Data/value.cxx b/libecs/source/Core/Data/value.cxx index 0498d13f..c04473ae 100644 --- a/libecs/source/Core/Data/value.cxx +++ b/libecs/source/Core/Data/value.cxx @@ -30,4 +30,7 @@ Type Value::type() const // FIXME: Remove the static_cast when GCC 12 releases static_cast(*this)); } + +bool List::operator==(const List &rhs) const { return items.size() == rhs.items.size(); } +auto List::operator<=>(const List &rhs) const { return items.size() <=> rhs.items.size(); } } // namespace pivot::ecs::data diff --git a/libpivot/sources/engine.cxx b/libpivot/sources/engine.cxx index fb724e40..0fd7d306 100644 --- a/libpivot/sources/engine.cxx +++ b/libpivot/sources/engine.cxx @@ -45,11 +45,37 @@ using namespace pivot::ecs; namespace pivot { Engine::Engine() - : m_scripting_engine(m_system_index, m_component_index, m_event_index, - pivot::ecs::script::interpreter::builtins::BuiltinContext{ - .isKeyPressed = std::bind_front(&Engine::isKeyPressed, this), - .selectCamera = std::bind_front(&Engine::setCurrentCamera, this), - }), + : m_scripting_engine( + m_system_index, m_component_index, m_event_index, + pivot::ecs::script::interpreter::builtins::BuiltinContext{ + .isKeyPressed = std::bind_front(&Engine::isKeyPressed, this), + .selectCamera = std::bind_front(&Engine::setCurrentCamera, this), + .createEntity = [this](const std::string &name) -> std::pair { + pivot::Entity createdEntityId = 0; + std::string actualName = name; + while (this->m_scene_manager.getCurrentScene() + .getEntityID(actualName) + .has_value()) { // while entity exists already + actualName = actualName + " - Copied"; + } + createdEntityId = this->m_scene_manager.getCurrentScene().CreateEntity(actualName); + return std::pair(createdEntityId, actualName); + }, + .removeEntity = + [this](const std::string &name) { + pivot::Entity createdEntityId = 0; + std::string actualName = name; + if (this->m_scene_manager.getCurrentScene() + .getEntityID(actualName) + .has_value()) // entity exists + this->m_scene_manager.getCurrentScene().DestroyEntity( + this->m_scene_manager.getCurrentScene().getEntityID(actualName).value()); + }, + .addComponent = [this](Entity entityId, const std::string &entity, const std::string &component) -> void { + // componentManager->getComponentId(component) + // scene->AddComponent() + return; + }}), m_default_camera_data(), m_default_camera_transform{.position = glm::vec3(0, 5, 0)}, m_default_camera{m_default_camera_data, m_default_camera_transform} diff --git a/libscript/CMakeLists.txt b/libscript/CMakeLists.txt index f6503b82..52ce3b86 100644 --- a/libscript/CMakeLists.txt +++ b/libscript/CMakeLists.txt @@ -22,5 +22,6 @@ build_tests( tests/test_escaped.cxx tests/test_decimals.cxx tests/test_multibyte.cxx + tests/test_entities.cxx tests/test_negative_numbers.cxx ) diff --git a/libscript/include/pivot/script/Builtins.hxx b/libscript/include/pivot/script/Builtins.hxx index c982b789..59a441f6 100644 --- a/libscript/include/pivot/script/Builtins.hxx +++ b/libscript/include/pivot/script/Builtins.hxx @@ -22,6 +22,15 @@ struct BuiltinContext { /// Select an entity as the new current camera std::function)> selectCamera; + /// Create an entity in the current scene + std::function(const std::string &)> createEntity; + + /// Remove an entity in the current scene + std::function removeEntity; + + /// Add a component to an entity + std::function addComponent; + /// Mock builtin context for unit testing static BuiltinContext mock() { @@ -66,6 +75,26 @@ data::Value builtin_sqrt(const std::vector ¶ms, const BuiltinCo /// Returns the absolute value of the given Number data::Value builtin_abs(const std::vector ¶ms, const BuiltinContext &context); +/// Boolean not(Boolean v) +/// Returns the not value of v +data::Value builtin_not(const std::vector ¶ms, const BuiltinContext &context); + +/// ScriptEntity createEntity(String name) +/// Returns the created entity just BAM +data::Value builtin_createEntity(const std::vector ¶ms, const BuiltinContext &context); + +/// void removeEntity(String name) +/// Removes the given entity from the scene if it exists +data::Value builtin_removeEntity(const std::vector ¶ms, const BuiltinContext &context); + +/// void addComponent(String entityToAddTheComponentTo, String theComponentToAddToTheEntity) +/// Returns nothing, but adds the component to the given entity +data::Value builtin_addComponent(const std::vector ¶ms, const BuiltinContext &context); + +/// void emitEvent(String eventName) +/// Emits the event +data::Value builtin_emitEvent(const std::vector ¶ms, const BuiltinContext &context); + /// String toString(Any val) /// Returns a string representation of the given Value data::Value builtin_toString(const std::vector ¶ms, const BuiltinContext &); @@ -78,6 +107,26 @@ data::Value builtin_vec3(const std::vector ¶ms, const BuiltinCo /// Returns a built Color value from the rgba parameters data::Value builtin_color(const std::vector ¶ms, const BuiltinContext &context); +/// List list(Any item1, Any item2 ...) +/// Returns a list with optional items to put inside +data::Value builtin_list(const std::vector ¶ms, const BuiltinContext &); + +/// Any at(List haystack, Number needle) +/// Returns the value at the given index in given list +data::Value builtin_at(const std::vector ¶ms, const BuiltinContext &); + +/// Number len(List list) +/// Returns the size of the list +data::Value builtin_len(const std::vector ¶ms, const BuiltinContext &); + +/// Void remove(List list, Number toRemove) +/// Removes the value at given index +data::Value builtin_remove(const std::vector ¶ms, const BuiltinContext &); + +/// Void push(List list, Any toPush1, any toPush2 ...) +/// At the values to the list +data::Value builtin_push(const std::vector ¶ms, const BuiltinContext &); + /// Void selectCamera(Entity entity) data::Value builtin_selectCamera(const std::vector ¶ms, const BuiltinContext &context); diff --git a/libscript/include/pivot/script/Interpreter.hxx b/libscript/include/pivot/script/Interpreter.hxx index b2710b0b..5a0bd97d 100644 --- a/libscript/include/pivot/script/Interpreter.hxx +++ b/libscript/include/pivot/script/Interpreter.hxx @@ -36,9 +36,9 @@ public: Interpreter(builtins::BuiltinContext context): m_builtinContext(context) {} /// Execute a SystemEntryPoint node by executing all of its statements - void executeSystem(const Node &systemEntry, const systems::Description &desc, - component::ArrayCombination::ComponentCombination &entity, event::EventWithComponent &trigger, - Stack &stack); + std::vector executeSystem(const Node &systemEntry, const systems::Description &desc, + component::ArrayCombination::ComponentCombination &entity, + event::EventWithComponent &trigger, Stack &stack); private: /// Execute a statement (used for recursion for blocks) @@ -55,6 +55,9 @@ private: /// Reference to the Window to get the input builtins::BuiltinContext m_builtinContext; + + /// List of events to return + std::vector m_events; }; // Private functions diff --git a/libscript/sources/Builtins.cxx b/libscript/sources/Builtins.cxx index d0bd4867..9b022e9c 100644 --- a/libscript/sources/Builtins.cxx +++ b/libscript/sources/Builtins.cxx @@ -45,8 +45,14 @@ data::Value builtin_print_stream(const std::vector ¶ms, std::os stream << "Asset(" << value.name << ")"; } else if constexpr (std::is_same_v) { stream << "vec3(" << value.x << "," << value.y << "," << value.z << ")"; + } else if constexpr (std::is_same_v) { + stream << "color(" << value.rgba[0] << "," << value.rgba[1] << "," << value.rgba[2] << "," + << value.rgba[3] << ")"; } else if constexpr (std::is_same_v) { stream << "EntityRef(" << (value.is_empty() ? "EMPTY" : std::to_string(value.ref).c_str()) << ")"; + } else if constexpr (std::is_same_v) { + stream << "List\t"; + builtin_print_stream((std::get((const data::Value &)value)).items, stream); } else { throw std::runtime_error("Code branch shouldn't execute."); } @@ -96,6 +102,37 @@ data::Value builtin_abs(const std::vector ¶ms, const BuiltinCon return data::Value(absVal); } +data::Value builtin_not(const std::vector ¶ms, const BuiltinContext &context) +{ + return (!std::get(params.at(0))); +} + +data::Value builtin_createEntity(const std::vector ¶ms, const BuiltinContext &context) +{ + std::pair entityId = context.createEntity(std::get(params.at(0))); + + data::ScriptEntity createdScriptEntity{data::Record{{"name", entityId.second}}, entityId.first}; + data::Value createdEntity = data::Value(createdScriptEntity); + return createdEntity; +} + +data::Value builtin_removeEntity(const std::vector ¶ms, const BuiltinContext &context) +{ + context.removeEntity(std::get(params.at(0))); + return data::Value(); +} + +data::Value builtin_emitEvent(const std::vector ¶ms, const BuiltinContext &context) +{ + std::cout << "Emitting event " << std::get(params.at(0)) << std::endl; + return data::Value(); +} + +data::Value builtin_addComponent(const std::vector ¶ms, const BuiltinContext &context) +{ + return data::Value(); +} + std::string removeTrailingZeroes(std::string str) { // Helper function until std::format is available in gcc str.erase(str.find_last_not_of('0') + 1, std::string::npos); @@ -403,6 +440,53 @@ data::Value builtin_color(const std::vector ¶ms, const BuiltinC (float)std::get(params.at(2)), (float)std::get(params.at(3))}}}; } +data::Value builtin_list(const std::vector ¶ms, const BuiltinContext &) +{ + data::List r; + + for (const data::Value ¶m: params) { r.items.push_back(param); } + return {r}; +} + +data::Value builtin_at(const std::vector ¶ms, const BuiltinContext &) +{ + size_t index = (size_t)(std::get(params.at(1))); + const data::List &list = std::get(params.at(0)); + if (index >= list.items.size()) { + logger.err("ERROR") << " by index 'at(" << index << ")' and size '" << list.items.size() << "'"; + throw InvalidOperation("Index out of list range."); + } + return list.items.at(index); +} + +data::Value builtin_len(const std::vector ¶ms, const BuiltinContext &) +{ + return data::Value{(double)std::get(params.at(0)).items.size()}; +} + +data::Value builtin_remove(const std::vector ¶ms, const BuiltinContext &) +{ + size_t index = (size_t)(std::get(params.at(1))); + const data::List &list = std::get(params.at(0)); + if (index >= list.items.size()) { + logger.err("ERROR") << " by index 'at(" << index << ")' and size '" << list.items.size() << "'"; + throw InvalidOperation("Index out of list range."); + } + data::List r; + for (size_t i = 0; i < list.items.size(); i++) + if (i != index) r.items.push_back(data::Value{list.items.at(i)}); + return data::Value{r}; +} + +data::Value builtin_push(const std::vector ¶ms, const BuiltinContext &) +{ + const data::List &list = std::get(params.at(0)); + data::List r; + for (const data::Value &v: list.items) r.items.push_back(v); + for (size_t i = 1; i < params.size(); i++) r.items.push_back(params.at(i)); + return data::Value{r}; +} + // Mathematical/Arithmetic operators -- end } // end of namespace pivot::ecs::script::interpreter::builtins diff --git a/libscript/sources/Engine.cxx b/libscript/sources/Engine.cxx index a4fc230f..2ae67e62 100644 --- a/libscript/sources/Engine.cxx +++ b/libscript/sources/Engine.cxx @@ -94,6 +94,7 @@ std::vector Engine::systemCallback(const systems::Description logger.err("Unregistered system '") << system.name << "'"; return {}; } + std::vector emittedEvents; const Node &systemEntry = _systems.at(system.name); // Avoid looking up for every entity for (auto entity: entities) { // For every entity, execute the system with it as parameter try { diff --git a/libscript/sources/Interpreter.cxx b/libscript/sources/Interpreter.cxx index 39e4dac8..fc399e08 100644 --- a/libscript/sources/Interpreter.cxx +++ b/libscript/sources/Interpreter.cxx @@ -12,9 +12,9 @@ namespace pivot::ecs::script::interpreter { const std::map gVariableTypes{ - {"Vector3", data::BasicType::Vec3}, {"Vector2", data::BasicType::Vec2}, {"Asset", data::BasicType::Asset}, - {"Number", data::BasicType::Number}, {"Boolean", data::BasicType::Boolean}, {"Color", data::BasicType::Color}, - {"String", data::BasicType::String}}; + {"Vector3", data::BasicType::Vec3}, {"Vector2", data::BasicType::Vec2}, {"Asset", data::BasicType::Asset}, + {"Number", data::BasicType::Number}, {"Boolean", data::BasicType::Boolean}, {"Color", data::BasicType::Color}, + {"String", data::BasicType::String}, {"Entity", data::BasicType::ScriptEntity}, {"List", data::BasicType::List}}; // Map builtin binary (two operands) operators, to their operator enum const std::map> gOperatorCallbacks = { {"*", interpreter::builtins::builtin_operator}, @@ -56,11 +56,32 @@ const std::unordered_map::max(), {{data::BasicType::String, data::BasicType::Number, data::BasicType::Integer, data::BasicType::Boolean, - data::BasicType::Asset, data::BasicType::Vec3, data::BasicType::EntityRef}}}}}, + data::BasicType::Color, data::BasicType::Asset, data::BasicType::Vec3, data::BasicType::List, + data::BasicType::EntityRef}}}}}, {"randint", {interpreter::builtins::builtin_randint, {1, {{data::BasicType::Number}}}}}, {"pow", {interpreter::builtins::builtin_power, {2, {{data::BasicType::Number}, {data::BasicType::Number}}}}}, {"sqrt", {interpreter::builtins::builtin_sqrt, {1, {{data::BasicType::Number}}}}}, {"abs", {interpreter::builtins::builtin_abs, {1, {{data::BasicType::Number}}}}}, + {"not", {interpreter::builtins::builtin_not, {1, {{data::BasicType::Boolean}}}}}, + {"createEntity", {interpreter::builtins::builtin_createEntity, {1, {{data::BasicType::String}}}}}, + {"removeEntity", {interpreter::builtins::builtin_removeEntity, {1, {{data::BasicType::String}}}}}, + {"emitEvent", {interpreter::builtins::builtin_emitEvent, {1, {{data::BasicType::String}}}}}, + {"addComponent", + {interpreter::builtins::builtin_addComponent, {2, {{data::BasicType::String}, {data::BasicType::String}}}}}, + {"list", + {interpreter::builtins::builtin_list, + {std::numeric_limits::max(), + {{data::BasicType::String, data::BasicType::Number, data::BasicType::Integer, data::BasicType::Boolean, + data::BasicType::Asset, data::BasicType::Vec3, data::BasicType::EntityRef}}}}}, + {"at", {interpreter::builtins::builtin_at, {2, {{data::BasicType::List}, {data::BasicType::Number}}}}}, + {"remove", {interpreter::builtins::builtin_remove, {2, {{data::BasicType::List}, {data::BasicType::Number}}}}}, + {"push", + {interpreter::builtins::builtin_push, + {std::numeric_limits::max(), + {{data::BasicType::String, data::BasicType::Number, data::BasicType::Integer, data::BasicType::Boolean, + data::BasicType::Asset, data::BasicType::Vec3, data::BasicType::List, data::BasicType::EntityRef, + data::BasicType::Color}}}}}, + {"len", {interpreter::builtins::builtin_len, {1, {{data::BasicType::List}}}}}, {"vec3", {interpreter::builtins::builtin_vec3, {3, {{data::BasicType::Number}, {data::BasicType::Number}, {data::BasicType::Number}}}}}, @@ -69,6 +90,25 @@ const std::unordered_map eventDescriptions = { + {"Tick", + { + .name = "Tick", + .entities = {}, + .payload = pivot::ecs::data::BasicType::Number, + .payloadName = "delta", + .provenance = pivot::ecs::Provenance::builtin(), + }}, + {"KeyPress", + { + .name = "KeyPress", + .entities = {}, + .payload = pivot::ecs::data::BasicType::String, + .payloadName = "key", + .provenance = pivot::ecs::Provenance::builtin(), + }}, +}; + // Public functions ( can be called anywhere ) // This will go through a file's tree and register all component/system declarations into the global index @@ -130,9 +170,10 @@ std::vector registerDeclarations(const Node &file, compone } // This will execute a SystemEntryPoint node by executing all of its statements -void Interpreter::executeSystem(const Node &systemEntry, const systems::Description &desc, - component::ArrayCombination::ComponentCombination &entityComponentCombination, - event::EventWithComponent &trigger, Stack &stack) +std::vector +Interpreter::executeSystem(const Node &systemEntry, const systems::Description &desc, + component::ArrayCombination::ComponentCombination &entityComponentCombination, + event::EventWithComponent &trigger, Stack &stack) { PROFILE_FUNCTION(); // systemComponents : [ "Position", "Velocity" ] @@ -158,6 +199,7 @@ void Interpreter::executeSystem(const Node &systemEntry, const systems::Descript for (std::size_t i = 0; i < desc.eventListener.entities.size(); i++) { stack.updateEntity(desc.eventListener.entities[i], trigger.components[i]); } + return m_events; } // Private functions (never called elsewhere than this file and tests) @@ -312,6 +354,12 @@ data::Value Interpreter::executeFunction(const Node &functionCall, const Stack & validateParams(parameters, gBuiltinsCallbacks.at(callee.value).second.first, gBuiltinsCallbacks.at(callee.value).second.second, callee.value); // pair is types> + if (callee.value == "emitEvent") { + event::Event evt = {.description = eventDescriptions.at(std::get(parameters.at(0))), + .entities = {}, + .payload = (0.13)}; + m_events.push_back(evt); + } return gBuiltinsCallbacks.at(callee.value) .first(parameters, m_builtinContext); // return the return value of the built-in } diff --git a/libscript/sources/Parser.cxx b/libscript/sources/Parser.cxx index 469b8d92..d15ac9fb 100644 --- a/libscript/sources/Parser.cxx +++ b/libscript/sources/Parser.cxx @@ -29,7 +29,9 @@ const std::unordered_map gVariableTypes{{"Vector3" {"Number", data::BasicType::Number}, {"Boolean", data::BasicType::Boolean}, {"Color", data::BasicType::Number}, - {"String", data::BasicType::String}}; + {"Entity", data::BasicType::ScriptEntity}, + {"String", data::BasicType::String}, + {"List", data::BasicType::List}}; // Public methods diff --git a/libscript/sources/Stack.cxx b/libscript/sources/Stack.cxx index eebb2843..2503d10e 100644 --- a/libscript/sources/Stack.cxx +++ b/libscript/sources/Stack.cxx @@ -104,8 +104,15 @@ data::Value &Stack::findMut(const std::string &name, data::Record &where) throw InvalidException("Stack Find: Unknown Variable."); } else if (!std::holds_alternative( where.at(accessingVar))) { // record contains variable, but it is not a record - logger.err("ERROR") << " with variable " << accessingVar << " of type " << where.at(accessingVar).type(); - throw InvalidException("Stack Find: Variable is not a Record"); + if (std::holds_alternative(where.at(accessingVar))) { + return findMut(name.substr(dot + 1), + std::get(where.at(accessingVar)) + .components); // recursive call on the rest of the access chain + + } else { + logger.err("ERROR") << " with variable " << accessingVar << " of type " << where.at(accessingVar).type(); + throw InvalidException("Stack Find: Variable is not a Record"); + } } return findMut(name.substr(dot + 1), std::get(where.at(accessingVar))); // recursive call on the rest of the access chain @@ -141,7 +148,12 @@ const data::Value Stack::find(const std::string &name, const data::Record &where << where.at(accessingVar).type(); throw InvalidException("Stack Find: Can only access field 'x' 'y' or 'z' of Vector3"); } - } else { // if it is neither a record nor a vector3 throw + } else if (std::holds_alternative( + where.at(accessingVar))) { // but it might be a scriptEntity + return find(name.substr(dot + 1), + std::get(where.at(accessingVar)) + .components); // recursive call on the rest of the access chain + } else { // if it is neither a record nor a vector3 nor a ScriptEntity throw logger.err("ERROR") << " with variable " << accessingVar << " of type " << where.at(accessingVar).type(); throw InvalidException("Stack Find: Variable is not a Record"); } diff --git a/libscript/tests/Scene1.json b/libscript/tests/Scene1.json new file mode 100644 index 00000000..6c015790 --- /dev/null +++ b/libscript/tests/Scene1.json @@ -0,0 +1,20 @@ +{ + "assets": [], + "components": [ + { + "Once": { + "trigger": false + }, + "Tag": { + "name": "Player" + } + } + ], + "name": "Default", + "scripts": [ + "a.pivotscript" + ], + "systems": [ + "S" + ] +} diff --git a/libscript/tests/a.pivotscript b/libscript/tests/a.pivotscript new file mode 100644 index 00000000..9c46161d --- /dev/null +++ b/libscript/tests/a.pivotscript @@ -0,0 +1,35 @@ +component Once + Boolean trigger + +system S(anyEntity) event KeyPress(String key) + if key == "N" + Entity monster = createEntity("monster1") + Entity player = createEntity("player") + if key == "A" + removeEntity("monster1") + removeEntity("player") + if key == "Z" + removeEntity("monster1 - Copied") + removeEntity("player - Copied") + if key == "E" + removeEntity("monster1 - Copied - Copied") + removeEntity("player - Copied - Copied") + if key == "R" + removeEntity("monster1 - Copied - Copied - Copied") + removeEntity("player - Copied - Copied - Copied") + if key == "T" + emitEvent("Tick") + if key == "L" + List newList = list(0, 1, 2) + print("Print list: ", newList) + print("Print list size: ", len(newList)) + print("Print list at 0: ", at(newList, 0)) + print("Print list at 1: ", at(newList, 1)) + print("Removing item at index 0...") + newList = remove(newList, 1) + print("Print list: ", newList) + newList = remove(newList, 0) + newList = remove(newList, 0) + print("Print list: ", newList) + newList = push(newList, 0, "lol", vec3(1,2,3), color(255,255,255,255)) + print("Print list: ", newList) diff --git a/libscript/tests/test_builtins.cxx b/libscript/tests/test_builtins.cxx index 3cfa0bf4..7c805f93 100644 --- a/libscript/tests/test_builtins.cxx +++ b/libscript/tests/test_builtins.cxx @@ -76,3 +76,11 @@ TEST_CASE("Builtin color", "[script][builtin]") REQUIRE(std::holds_alternative(result)); REQUIRE(std::get(result) == Color{4, 255, 2, 1}); } + +TEST_CASE("Builtin not", "[script][builtin]") +{ + auto context = BuiltinContext::mock(); + + REQUIRE(std::get(builtin_not({true}, context)) == false); + REQUIRE(std::get(builtin_not({false}, context)) == true); +} \ No newline at end of file diff --git a/libscript/tests/test_decimals.cxx b/libscript/tests/test_decimals.cxx index 975b93c7..ab4cb2ea 100644 --- a/libscript/tests/test_decimals.cxx +++ b/libscript/tests/test_decimals.cxx @@ -9,7 +9,7 @@ using namespace pivot::ecs; TEST_CASE("Scripting-Interpreter-Decimals") { - logger.start(); + // logger.start(); logger.info("------Interpreter Decimals------") << "Start"; diff --git a/libscript/tests/test_entities.cxx b/libscript/tests/test_entities.cxx new file mode 100644 index 00000000..c1b0f822 --- /dev/null +++ b/libscript/tests/test_entities.cxx @@ -0,0 +1,78 @@ +#include "pivot/ecs/Core/SceneManager.hxx" +#include "pivot/script/Engine.hxx" +#include +#include +#include + +using namespace pivot::ecs; + +TEST_CASE("Scripting-Interpreter-Entities") +{ + logger.start(); + + logger.info() << "------Interpreter - Entities------start"; + + component::Index cind; + systems::Index sind; + event::Index eind; + SceneManager m_scene_manager{}; + m_scene_manager.registerScene("Scene1"); + m_scene_manager.setCurrentSceneId(m_scene_manager.getSceneId("Scene1").value()); + script::Engine engine( + sind, cind, eind, + pivot::ecs::script::interpreter::builtins::BuiltinContext{ + .isKeyPressed = [](auto) { return false; }, + .selectCamera = [](auto) { return false; }, + .createEntity = [&m_scene_manager](const std::string &name) -> std::pair { + // EntityId = currentScene->createEntity(name); + pivot::Entity createdEntityId = 0; + if (m_scene_manager.getCurrentScene().getEntityID(name).has_value()) { // entity exists already + std::cout << "duplicating " << std::endl; + createdEntityId = m_scene_manager.getCurrentScene().CreateEntity(name + " - Copied"); + return std::pair(createdEntityId, name + " - Copied"); + } else { // entity doesn't already exist + std::cout << "new one " << std::endl; + createdEntityId = m_scene_manager.getCurrentScene().CreateEntity(name); + return std::pair(createdEntityId, name); + } + }, + .addComponent = [](Entity entityId, const std::string &entity, const std::string &component) -> void { + // componentManager->getComponentId(component) + // scene->AddComponent() + return; + }}); + // std::string file = "C:/Users/Najo/eip/pivot/libscript/tests/test_events.pivotscript"; + // engine.loadFile(file); + + std::string fileContent = "component Once\n" + "\tBoolean trigger\n" + "event Tick\n" + "\tNumber dt\n" + "event KeyPress\n" + "\tString key\n" + "system S(anyEntity) event Tick(Number deltaTime)\n" + "\temit Tick(12)\n" + "\temit KeyPress(\"m\")\n"; + + engine.loadFile(fileContent, true); + + REQUIRE(sind.getDescription("S").has_value()); + REQUIRE(cind.getDescription("Once").has_value()); + + auto Oncedescription = cind.getDescription("Once").value(); + auto Sdescription = sind.getDescription("S").value(); + auto array1 = Oncedescription.createContainer(Oncedescription); + std::vector entity = {data::Record{{"trigger", false}}}; + array1->setValueForEntity(0, entity.at(0)); + component::ArrayCombination combinations{{std::ref(*array1)}}; + event::EventWithComponent evt = { + .event = event::Event{.description = Sdescription.eventListener, .entities = {1, 2}, .payload = 0.12}}; + + std::vector triggeredEvents = Sdescription.system(Sdescription, combinations, evt); + + REQUIRE(triggeredEvents.size() == 2); + REQUIRE(triggeredEvents.at(0).description.name == "Tick"); + REQUIRE(triggeredEvents.at(1).description.name == "KeyPress"); + + logger.info() << "------Interpreter - Entities------end"; +}