Skip to content
This repository has been archived by the owner on Aug 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #253 from EIP-Pivot/feat/script/entities
Browse files Browse the repository at this point in the history
  • Loading branch information
zcorniere authored Jan 18, 2023
2 parents a93071e + 5eda5ae commit 44d7766
Show file tree
Hide file tree
Showing 18 changed files with 440 additions and 22 deletions.
10 changes: 10 additions & 0 deletions editor/include/ImGuiCore/ValueInput.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -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); },
Expand Down
13 changes: 13 additions & 0 deletions libecs/include/pivot/ecs/Core/Data/type.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 <typename T>
constexpr std::optional<BasicType> basic_type_representation = std::nullopt;

Expand All @@ -100,6 +109,10 @@ template <>
constexpr std::optional<BasicType> basic_type_representation<Void> = BasicType::Void;
template <>
constexpr std::optional<BasicType> basic_type_representation<EntityRef> = BasicType::EntityRef;
template <>
constexpr std::optional<BasicType> basic_type_representation<ScriptEntity> = BasicType::ScriptEntity;
template <>
constexpr std::optional<BasicType> basic_type_representation<List> = BasicType::List;

} // namespace pivot::ecs::data

Expand Down
29 changes: 27 additions & 2 deletions libecs/include/pivot/ecs/Core/Data/value.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,31 @@ struct Record : public std::map<std::string, Value> {
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<data::Value> 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 :
Expand All @@ -35,8 +60,8 @@ struct Record : public std::map<std::string, Value> {
* - Void (no value)
* - Entity (entity reference)
*/
struct Value
: public std::variant<std::string, double, int, bool, glm::vec3, glm::vec2, Record, Asset, Color, Void, EntityRef> {
struct Value : public std::variant<std::string, double, int, bool, glm::vec3, glm::vec2, Record, Asset, Color, Void,
EntityRef, ScriptEntity, List> {
using variant::variant;

/// Returns the Type corresponding to this Value
Expand Down
3 changes: 3 additions & 0 deletions libecs/source/Core/Data/value.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ Type Value::type() const
// FIXME: Remove the static_cast when GCC 12 releases
static_cast<const Value::variant &>(*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
36 changes: 31 additions & 5 deletions libpivot/sources/engine.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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, std::string> {
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<pivot::Entity, std::string>(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}
Expand Down
1 change: 1 addition & 0 deletions libscript/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
49 changes: 49 additions & 0 deletions libscript/include/pivot/script/Builtins.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ struct BuiltinContext {
/// Select an entity as the new current camera
std::function<void(std::optional<Entity>)> selectCamera;

/// Create an entity in the current scene
std::function<std::pair<pivot::Entity, std::string>(const std::string &)> createEntity;

/// Remove an entity in the current scene
std::function<void(const std::string &)> removeEntity;

/// Add a component to an entity
std::function<void(pivot::Entity, const std::string &, const std::string &)> addComponent;

/// Mock builtin context for unit testing
static BuiltinContext mock()
{
Expand Down Expand Up @@ -66,6 +75,26 @@ data::Value builtin_sqrt(const std::vector<data::Value> &params, const BuiltinCo
/// Returns the absolute value of the given Number
data::Value builtin_abs(const std::vector<data::Value> &params, const BuiltinContext &context);

/// Boolean not(Boolean v)
/// Returns the not value of v
data::Value builtin_not(const std::vector<data::Value> &params, const BuiltinContext &context);

/// ScriptEntity createEntity(String name)
/// Returns the created entity just BAM
data::Value builtin_createEntity(const std::vector<data::Value> &params, const BuiltinContext &context);

/// void removeEntity(String name)
/// Removes the given entity from the scene if it exists
data::Value builtin_removeEntity(const std::vector<data::Value> &params, 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<data::Value> &params, const BuiltinContext &context);

/// void emitEvent(String eventName)
/// Emits the event
data::Value builtin_emitEvent(const std::vector<data::Value> &params, const BuiltinContext &context);

/// String toString(Any val)
/// Returns a string representation of the given Value
data::Value builtin_toString(const std::vector<data::Value> &params, const BuiltinContext &);
Expand All @@ -78,6 +107,26 @@ data::Value builtin_vec3(const std::vector<data::Value> &params, const BuiltinCo
/// Returns a built Color value from the rgba parameters
data::Value builtin_color(const std::vector<data::Value> &params, 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<data::Value> &params, 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<data::Value> &params, const BuiltinContext &);

/// Number len(List list)
/// Returns the size of the list
data::Value builtin_len(const std::vector<data::Value> &params, const BuiltinContext &);

/// Void remove(List list, Number toRemove)
/// Removes the value at given index
data::Value builtin_remove(const std::vector<data::Value> &params, const BuiltinContext &);

/// Void push(List list, Any toPush1, any toPush2 ...)
/// At the values to the list
data::Value builtin_push(const std::vector<data::Value> &params, const BuiltinContext &);

/// Void selectCamera(Entity entity)
data::Value builtin_selectCamera(const std::vector<data::Value> &params, const BuiltinContext &context);

Expand Down
9 changes: 6 additions & 3 deletions libscript/include/pivot/script/Interpreter.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -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<ecs::event::Event> 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)
Expand All @@ -55,6 +55,9 @@ private:

/// Reference to the Window to get the input
builtins::BuiltinContext m_builtinContext;

/// List of events to return
std::vector<ecs::event::Event> m_events;
};

// Private functions
Expand Down
84 changes: 84 additions & 0 deletions libscript/sources/Builtins.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,14 @@ data::Value builtin_print_stream(const std::vector<data::Value> &params, std::os
stream << "Asset(" << value.name << ")";
} else if constexpr (std::is_same_v<type, glm::vec3>) {
stream << "vec3(" << value.x << "," << value.y << "," << value.z << ")";
} else if constexpr (std::is_same_v<type, data::Color>) {
stream << "color(" << value.rgba[0] << "," << value.rgba[1] << "," << value.rgba[2] << ","
<< value.rgba[3] << ")";
} else if constexpr (std::is_same_v<type, pivot::EntityRef>) {
stream << "EntityRef(" << (value.is_empty() ? "EMPTY" : std::to_string(value.ref).c_str()) << ")";
} else if constexpr (std::is_same_v<type, data::List>) {
stream << "List\t";
builtin_print_stream((std::get<data::List>((const data::Value &)value)).items, stream);
} else {
throw std::runtime_error("Code branch shouldn't execute.");
}
Expand Down Expand Up @@ -96,6 +102,37 @@ data::Value builtin_abs(const std::vector<data::Value> &params, const BuiltinCon
return data::Value(absVal);
}

data::Value builtin_not(const std::vector<data::Value> &params, const BuiltinContext &context)
{
return (!std::get<bool>(params.at(0)));
}

data::Value builtin_createEntity(const std::vector<data::Value> &params, const BuiltinContext &context)
{
std::pair<pivot::Entity, std::string> entityId = context.createEntity(std::get<std::string>(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<data::Value> &params, const BuiltinContext &context)
{
context.removeEntity(std::get<std::string>(params.at(0)));
return data::Value();
}

data::Value builtin_emitEvent(const std::vector<data::Value> &params, const BuiltinContext &context)
{
std::cout << "Emitting event " << std::get<std::string>(params.at(0)) << std::endl;
return data::Value();
}

data::Value builtin_addComponent(const std::vector<data::Value> &params, 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);
Expand Down Expand Up @@ -403,6 +440,53 @@ data::Value builtin_color(const std::vector<data::Value> &params, const BuiltinC
(float)std::get<double>(params.at(2)), (float)std::get<double>(params.at(3))}}};
}

data::Value builtin_list(const std::vector<data::Value> &params, const BuiltinContext &)
{
data::List r;

for (const data::Value &param: params) { r.items.push_back(param); }
return {r};
}

data::Value builtin_at(const std::vector<data::Value> &params, const BuiltinContext &)
{
size_t index = (size_t)(std::get<double>(params.at(1)));
const data::List &list = std::get<data::List>(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<data::Value> &params, const BuiltinContext &)
{
return data::Value{(double)std::get<data::List>(params.at(0)).items.size()};
}

data::Value builtin_remove(const std::vector<data::Value> &params, const BuiltinContext &)
{
size_t index = (size_t)(std::get<double>(params.at(1)));
const data::List &list = std::get<data::List>(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<data::Value> &params, const BuiltinContext &)
{
const data::List &list = std::get<data::List>(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
1 change: 1 addition & 0 deletions libscript/sources/Engine.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ std::vector<ecs::event::Event> Engine::systemCallback(const systems::Description
logger.err("Unregistered system '") << system.name << "'";
return {};
}
std::vector<ecs::event::Event> 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 {
Expand Down
Loading

0 comments on commit 44d7766

Please sign in to comment.