Skip to content

Commit

Permalink
added repeat while
Browse files Browse the repository at this point in the history
  • Loading branch information
vboxuser committed Feb 5, 2024
1 parent 10755ee commit 2a4368d
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 199 deletions.
56 changes: 45 additions & 11 deletions core/include/cubos/core/ecs/cubos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ namespace cubos::core::ecs
/// @return Reference to this object, for chaining.
TagBuilder& after(const std::string& tag);

/// @brief Makes the current tag inherit from given tag.
/// @param tag Tag to be inherited from.
/// @return Reference to this object, for chaining.
TagBuilder& tagged(const std::string& tag);

/// @brief Adds a condition to the current tag. If this condition returns false, systems
/// with this tag will not be executed. For the tagged systems to run, all conditions must
/// return true.
Expand All @@ -79,28 +84,46 @@ namespace cubos::core::ecs
template <typename F>
TagBuilder& runIf(F func);

/// @brief Adds a repeat condition to the current tag, also making it a group.
/// @param func Condition function.
/// @return Reference to this object, for chaining.
template <typename F>
TagBuilder& repeatWhile(F func);

private:
core::ecs::Dispatcher& mDispatcher;
std::vector<std::string>& mTags;
};

/// @brief Used to make groups of tags.
/// @ingroup engine
/// @brief Used to create groups and subgroups.
/// @ingroup core-ecs
class GroupBuilder
{
public:
/// @brief Construct.
/// @param dispatcher Dispatcher being configured
/// @param tags Vector which stores the tags for this dispatcher.
/// @param grouptag Tag for the group.
/// @return Reference to this object, for chaining.
GroupBuilder(core::ecs::Dispatcher& dispatcher, const std::string& grouptag);

/// @brief Creates a subgroup.
/// @param tag Tag for the subgroup.
/// @return Reference to this object, for chaining.
GroupBuilder(core::ecs::Dispatcher& dispatcher, std::vector<std::string>& tags);
GroupBuilder& subgroup();


/// @brief Ends a group by reseting current group.
/// @return Reference to this object, for chaining.
GroupBuilder& endgroup();

/// @brief Sets the group to have a repeatWhile condition.
/// @param func Condition function.
/// @return Reference to this object, for chaining.
template <typename F>
GroupBuilder& repeatWhile(F func);

private:
core::ecs::Dispatcher& mDispatcher;
std::vector<std::string>& mTags;
const std::string& mgrouptag;
};

/// @brief Used to chain configurations related to systems
Expand Down Expand Up @@ -128,6 +151,11 @@ namespace cubos::core::ecs
/// @return Reference to this object, for chaining.
SystemBuilder& after(const std::string& tag);

/// @brief Sets the current system to be executed inside a group.
/// @param grouptag Grouptag of the group.
/// @return Reference to this object, for chaining.
SystemBuilder& ingroup(const std::string& grouptag);

/// @brief Adds a condition to the current system. If this condition returns false, the
/// system will not be executed. For a system to run, all conditions must return true.
/// @tparam F Condition system type.
Expand Down Expand Up @@ -172,11 +200,6 @@ namespace cubos::core::ecs
template <typename R, typename... TArgs>
Cubos& addResource(TArgs... args);

/// @brief Returns a @ref groupBuilder to configure the given group.
/// @param tags Tags that will be in the group.
/// @return @ref groupBuilder used to configure the group.
GroupBuilder group(const std::string& tag);

/// @brief Adds a new component type to the engine.
/// @tparam C Type of the component.
/// @return Reference to this object, for chaining.
Expand Down Expand Up @@ -209,6 +232,11 @@ namespace cubos::core::ecs
/// @return @ref TagBuilder used to configure the tag.
TagBuilder startupTag(const std::string& tag);

/// @brief creates a group.
/// @param tag Tag for the group.
/// @return @ref GroupBuilder used to configure the group.
GroupBuilder group(const std::string& tag);

/// @brief Adds a new system to the engine, which will be executed at every iteration of
/// the main loop.
/// @tparam F Type of the system function.
Expand Down Expand Up @@ -249,6 +277,12 @@ namespace cubos::core::ecs
return *this;
}

template <typename F>
TagBuilder& TagBuilder::repeatWhile(F func){
mDispatcher.tagRepeatWhile(func);
return *this;
}

template <typename F>
SystemBuilder& SystemBuilder::runIf(F func)
{
Expand Down
185 changes: 144 additions & 41 deletions core/include/cubos/core/ecs/system/dispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ namespace cubos::core::ecs
/// @param tag Tag to add.
void addTag(const std::string& tag);

/// @brief Adds a group.
/// @param tag Tags to add.
void addGroup(const std::string& tag);

/// @brief Makes the current tag inherit the settings of another tag.
/// @param tag Tag to inherit from.
void tagInheritTag(const std::string& tag);
Expand All @@ -83,6 +79,15 @@ namespace cubos::core::ecs
template <typename F>
void tagAddCondition(F func);

/// @brief Adds a repeat condition to the current tag.
/// @tparam F Condition type.
/// @param func Condition to add.
template <typename F>
void tagRepeatWhile(F func);

/// @brief Adds a (sub)group to the current group.
void groupAddGroup();

/// @brief Adds a system, and sets it as the current system for further configuration.
/// @tparam F System type.
/// @param func System to add.
Expand All @@ -93,6 +98,10 @@ namespace cubos::core::ecs
/// @param tag Tag to run under.
void systemAddTag(const std::string& tag);

/// @brief Links a system to a certain group.
/// @param grouptag Tag of the group.
void systemAddGroup(const std::string& grouptag);

/// @brief Sets the current system to run after the tag.
/// @param tag Tag to run after.
void systemSetAfterTag(const std::string& tag);
Expand All @@ -118,11 +127,9 @@ namespace cubos::core::ecs
/// @param cmds Command buffer.
void callSystems(World& world, CommandBuffer& cmds);

private:
struct Dependency;
struct SystemSettings;
struct System;
struct Group;

/// @brief Internal class to specify system dependencies
struct Dependency
Expand All @@ -131,26 +138,6 @@ namespace cubos::core::ecs
std::vector<System*> system;
};

/// @brief Internal class to specify system groups
struct Group
{
std::vector<Group> groups;
std::vector<std::string> tags;
std::vector<System*> systems;
std::vector<Group> before_subgroups;
std::vector<Group> after_subgroups;

Group(std::vector<Group> mgroups, std::vector<std::string> mtags, std::vector<System*> msystems,
std::vector<Group> mbefore_subgroups, std::vector<Group> mafter_subgroups)
: groups(mgroups)
, tags(mtags)
, systems(msystems)
, before_subgroups(mbefore_subgroups)
, after_subgroups(mafter_subgroups)
{
}
};

/// @brief Internal class with settings pertaining to system/tag execution
struct SystemSettings
{
Expand All @@ -168,8 +155,128 @@ namespace cubos::core::ecs
std::shared_ptr<SystemSettings> settings;
std::shared_ptr<AnySystemWrapper<void>> system;
std::unordered_set<std::string> tags;
std::string grouptag = "main";
};

class Step
{
public:
virtual ~Step() = default;
virtual void run(World& world, CommandBuffer& cmds,
std::vector<std::shared_ptr<AnySystemWrapper<bool>>> mConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRunConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRetConditions) = 0;
virtual void prepare(World& world) = 0;
};

class SystemStep : public Step
{
public:
SystemStep(const System* system)
: system(system)
{
}
void run(World& world, CommandBuffer& cmds,
std::vector<std::shared_ptr<AnySystemWrapper<bool>>> mConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRunConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRetConditions);
void prepare(World& world);

private:
const System* system;
};

class GroupStep : public Step, public std::enable_shared_from_this<Step>
{
public:
GroupStep(const std::string& grouptag, const std::shared_ptr<GroupStep> parent_step)
: grouptag(grouptag)
, parent_step(parent_step)
{
}
void run(World& world, CommandBuffer& cmds,
std::vector<std::shared_ptr<AnySystemWrapper<bool>>> mConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRunConditions,
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> mRetConditions);
void prepare(World& world);

void addSystemStep(const System* system)
{
steps.insert(steps.begin(), std::make_shared<SystemStep>(system));
}

std::shared_ptr<GroupStep> addGroupStep(const std::string& grouptag,

Check warning on line 208 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L208

Added line #L208 was not covered by tests
const std::shared_ptr<GroupStep>& parent)
{
std::shared_ptr<GroupStep> newStep = std::make_shared<GroupStep>(grouptag, parent);
steps.insert(steps.begin(), newStep);
return newStep;

Check warning on line 213 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L211-L213

Added lines #L211 - L213 were not covered by tests
}

void moveToFront(const std::shared_ptr<Step>& step)

Check warning on line 216 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L216

Added line #L216 was not covered by tests
{
auto it = std::find(steps.begin(), steps.end(), step);
if (it != steps.end())

Check warning on line 219 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L218-L219

Added lines #L218 - L219 were not covered by tests
{
std::rotate(steps.begin(), it, it + 1);

Check warning on line 221 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L221

Added line #L221 was not covered by tests
}
}

std::shared_ptr<GroupStep> FindGroup(const std::string& tag)
{
if (tag == grouptag)
{
return std::make_shared<GroupStep>(*this);

Check warning on line 229 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L229

Added line #L229 was not covered by tests
}
else
{
for (const auto& step : this->steps)
{
if (auto groupStepPtr = std::dynamic_pointer_cast<GroupStep>(step))

Check warning on line 235 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L235

Added line #L235 was not covered by tests
{
return groupStepPtr->FindGroup(tag);

Check warning on line 237 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L237

Added line #L237 was not covered by tests
}
}
}
return nullptr;
}

void QueueSystem(const std::string& system_grouptag, System* system)
{
if (system_grouptag == this->grouptag)
{
addSystemStep(system);

if (this->grouptag != "main")
{
this->parent_step->moveToFront(shared_from_this());

Check warning on line 252 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L252

Added line #L252 was not covered by tests
}
return;
}
else
{
for (const auto& step : this->steps)

Check warning on line 258 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L258

Added line #L258 was not covered by tests
{
if (auto groupStepPtr = std::dynamic_pointer_cast<GroupStep>(step))

Check warning on line 260 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L260

Added line #L260 was not covered by tests
{
groupStepPtr->QueueSystem(system_grouptag, system);

Check warning on line 262 in core/include/cubos/core/ecs/system/dispatcher.hpp

View check run for this annotation

Codecov / codecov/patch

core/include/cubos/core/ecs/system/dispatcher.hpp#L262

Added line #L262 was not covered by tests
}
}
}
}

const std::string& getGroupTag(){
return grouptag;
}
std::bitset<CUBOS_CORE_DISPATCHER_MAX_CONDITIONS> conditions;

private:
const std::string grouptag;
std::shared_ptr<GroupStep> parent_step;
std::vector<std::shared_ptr<Step>> steps;
};

private:
/// @brief Internal class used to implement a DFS algorithm for call chain compilation
struct DFSNode
{
Expand All @@ -190,23 +297,11 @@ namespace cubos::core::ecs
/// @return True if a cycle was detected, false if otherwise.
bool dfsVisit(DFSNode& node, std::vector<DFSNode>& nodes);

/// @param system system pointer.
/// @return The group that corresponds to the system.
bool FindGroup(Group&, Group* parent_group, System* system);

void prepareGroup(Group& group, World& world);

/// @brief Copies settings from inherited tags to this system, recursively solving nested
/// inheritance.
/// @param settings Settings to handle inheritance for.
void handleTagInheritance(std::shared_ptr<SystemSettings>& settings);

/// @brief Calls all systems in a group
/// @param group Group to call the systems in.
/// @param world World to call the systems in.
/// @param cmds Command buffer.
void runGroup(Group group, World& world, CommandBuffer& cmds);

/// @brief Assign a condition a bit in the condition bitset, and returns that assigned bit.
/// @ŧparam F Condition type.
/// @param func Condition to assign a bit for.
Expand All @@ -216,8 +311,6 @@ namespace cubos::core::ecs

// Variables for holding information before call chain is compiled.

std::vector<Group> mUnorderedGroups;
Group* mCurrGroup = nullptr; ///< Current group.
std::vector<System*> mPendingSystems; ///< All systems.
std::map<std::string, std::shared_ptr<SystemSettings>> mTagSettings; ///< All tags.
std::vector<std::shared_ptr<AnySystemWrapper<bool>>> mConditions; ///< All conditions.
Expand All @@ -230,8 +323,9 @@ namespace cubos::core::ecs
// Variables for holding information after call chain is compiled.

std::vector<System*> mSystems; ///< Compiled order of running systems.
std::vector<Group> mGroups; ///< Compiled order of running groups.
bool mPrepared = false; ///< Whether the systems are prepared for execution.
std::shared_ptr<GroupStep> mMainStep = std::make_shared<GroupStep>("main", nullptr);
std::shared_ptr<GroupStep> mCurrGroup = mMainStep;
};

template <typename F>
Expand All @@ -242,6 +336,15 @@ namespace cubos::core::ecs
mTagSettings[mCurrTag]->conditions |= bit;
}

template <typename F>
void Dispatcher::tagRepeatWhile(F func)
{
ENSURE_CURR_TAG();
groupAddGroup();
auto bit = assignConditionBit(func);
mCurrGroup->conditions |= bit;
}

template <typename F>
void Dispatcher::addSystem(F func)
{
Expand Down
Loading

0 comments on commit 2a4368d

Please sign in to comment.