| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
📝 Walkthrough
WalkthroughMoved many inline/template implementations out of headers into .ipp/.cpp files across Id, Entity/EntityId, Core, schedulers, plugins, systems, and time; added corresponding .ipp implementations and updated build globs to include .ipp files. No behavioral changes announced beyond new/relocated APIs. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labelsenhancement Suggested reviewers
Poem🚥 Pre-merge checks | ✅ 4 | ❌ 1 ❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches 📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ ShareComment @coderabbitai help to get the list of available commands and usage tips. |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)src/engine/src/scheduler/SchedulerContainer.hpp (1)🤖 Prompt for all review comments with AI agents27-27: Consider using noexcept instead of throw().
The throw() exception specification is deprecated since C++11 and removed in C++17. The base class std::exception::what() uses noexcept in modern C++.
♻️ Suggested fix🤖 Prompt for AI Agents- const char *what() const throw() override; + const char *what() const noexcept override;Verify each finding against the current code and only fix it if needed. In `@src/engine/src/scheduler/SchedulerContainer.hpp` at line 27, The declaration of the exception specification for the overridden what() method uses the deprecated throw() spec; update the SchedulerContainer::what() declaration (and its corresponding definition) to use noexcept instead of throw(), e.g. change "const char *what() const throw() override;" to use noexcept so the signature matches modern std::exception::what() and keeps the override valid.
Verify each finding against the current code and only fix it if needed. Inline comments: In `@src/engine/src/entity/EntityId.hpp`: - Around line 113-116: The shared map temporaryComponent must be protected against concurrent access: add an inline static mutex (e.g., temporaryComponentMutex) alongside temporaryComponent and take a lock (std::lock_guard or std::unique_lock) whenever AddTemporaryComponent and RemoveTemporaryComponents access or mutate the map (and any other access sites); use a shared_mutex if you want concurrent reads and exclusive writes, and ensure all reads are also properly synchronized to prevent data races and corruption. In `@src/engine/src/entity/EntityId.ipp`: - Line 12: The three non-template out-of-class definitions need the inline keyword to avoid ODR violations when EntityId.ipp is included in multiple translation units: mark bool EntityId::IsValid(const Engine::Core &core) const, void EntityId::RemoveTemporaryComponents(Core &core), and std::size_t std::hash<Engine::EntityId>::operator()(const Engine::EntityId &entityId) const noexcept as inline; update their declarations/definitions in EntityId.ipp accordingly so they can be duplicated across TUs without linker errors. In `@src/engine/src/scheduler/FixedTimeUpdate.cpp`: - Around line 6-13: Validate tickRate is strictly positive to avoid divide-by-zero: update the FixedTimeUpdate constructor and SetTickRate(float tickRate) to check tickRate > 0 and reject invalid values (e.g., throw std::invalid_argument with a clear message or assert) instead of assigning zero/negative to _tickRate; keep GetTickRate() unchanged and ensure callers like RunSystems() rely on this invariant so division by _tickRate is safe. In `@src/engine/src/scheduler/RelativeTimeUpdate.cpp`: - Around line 6-14: Validate and guard the tickRate value in Engine::Scheduler::RelativeTimeUpdate: in the constructor RelativeTimeUpdate(Core &core, float tickRate) and in SetTargetTickRate(float tickRate) ensure tickRate is > 0 before assigning to _tickRate (either throw std::invalid_argument or clamp to a small positive epsilon and/or log), so that _tickRate is never zero or negative when used as a divisor in RunSystems(); keep GetTargetTickRate unchanged. In `@src/engine/src/system/System.hpp`: - Around line 34-36: Update the GetSystems() doxygen comment to match the function signature: change the return description that currently mentions "vector" to "std::list" (or "list") so the doc for const std::list<std::unique_ptr<SystemBase>>& GetSystems() correctly reflects the returned container type; locate the comment above the GetSystems() declaration in System.hpp and update the `@return` text accordingly. - Line 54: SystemContainer::GetSystems() and SystemContainer::DeleteSystem() are defined non-inline in System.ipp which is included into System.hpp causing ODR/linker issues; fix by either marking both member functions as inline in their definitions in System.ipp or by moving their full definitions out of System.ipp into a dedicated System.cpp (and keep only declarations in System.hpp), ensuring the declarations in System.hpp correspond to the moved/inline definitions. In `@src/engine/xmake.lua`: - Around line 20-29: The xmake.lua header file globs omit entity implementation files: add_headerfiles currently includes "src/(entity/*.hpp)" but not "src/(entity/*.ipp)", so consumers that rely on Entity.hpp including an .ipp will break; update the add_headerfiles calls to also include "src/(entity/*.ipp)" (matching the pattern used for scheduler/system) so that entity implementation .ipp files are exported alongside the .hpp headers. --- Nitpick comments: In `@src/engine/src/scheduler/SchedulerContainer.hpp`: - Line 27: The declaration of the exception specification for the overridden what() method uses the deprecated throw() spec; update the SchedulerContainer::what() declaration (and its corresponding definition) to use noexcept instead of throw(), e.g. change "const char *what() const throw() override;" to use noexcept so the signature matches modern std::exception::what() and keeps the override valid.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4e1a8ad4-7651-4914-9a71-e32c54c326dd
📥 CommitsReviewing files that changed from the base of the PR and between eeb34c9 and 6e421a4.
📒 Files selected for processing (34)
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agentsVerify each finding against the current code and only fix it if needed. Inline comments: In `@src/engine/src/entity/EntityId.ipp`: - Around line 45-53: The shared static map temporaryComponent is accessed without synchronization in EntityId::AddTemporaryComponent and where it's iterated/cleared (lines ~86-91), creating TOCTOU and concurrent-modification races; fix by introducing a dedicated mutex (e.g., temporaryComponentMutex) and acquire a lock (std::lock_guard or std::scoped_lock) around all accesses and mutations of temporaryComponent, and replace the separate contains-then-assign pattern in AddTemporaryComponent with an atomic insert/emplace that uses the insertion result while still holding the lock to avoid race windows.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8a49d813-298b-4281-9049-7a0f68ebd876
📥 CommitsReviewing files that changed from the base of the PR and between 6e421a4 and 9666d32.
📒 Files selected for processing (3)
Sorry, something went wrong.
| decltype(auto) EntityId::AddTemporaryComponent(Engine::Core &core, TArgs &&...args) | ||
| { | ||
| if (!temporaryComponent.contains(std::type_index(typeid(TTempComponent)))) | ||
| { | ||
| temporaryComponent[std::type_index(typeid(TTempComponent))] = [](Core &c) { | ||
| Log::Debug(fmt::format("RemoveTemporaryComponent: {}", typeid(TTempComponent).name())); | ||
| c.GetRegistry().clear<TTempComponent>(); | ||
| }; | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue | 🔴 Critical
🧩 Analysis chain🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Shared temporary component state and synchronization usage:"
rg -n "temporaryComponent|mutex|lock_guard|scoped_lock" src/engine/src/entity/EntityId.hpp src/engine/src/entity/EntityId.ipp
echo
echo "Mutation/iteration points in EntityId.ipp:"
rg -n "temporaryComponent\\.contains|temporaryComponent\\[|temporaryComponent\\.clear|for \\(const auto \\&\\[typeIndex, func\\] : temporaryComponent\\)" src/engine/src/entity/EntityId.ippRepository: EngineSquared/EngineSquared
Length of output: 1071
🏁 Script executed:
# First, let's see the complete EntityId.hpp to understand the shared static state
cat -n src/engine/src/entity/EntityId.hpp | tail -20Repository: EngineSquared/EngineSquared
Length of output: 1323
🏁 Script executed:
# Now let's examine the complete EntityId.ipp file around the critical lines
head -95 src/engine/src/entity/EntityId.ipp | tail -55Repository: EngineSquared/EngineSquared
Length of output: 1857
🏁 Script executed:
# Let's also check if there are any includes of mutex or synchronization primitives
rg -n "#include.*mutex|#include.*lock|#include.*thread" src/engine/src/entity/EntityId.hpp src/engine/src/entity/EntityId.ippRepository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Check if there are any other synchronization mechanisms used elsewhere in the codebase for similar patterns
rg -n "std::mutex|std::lock_guard|std::scoped_lock" src/engine/src/entity/ --type cpp --type hppRepository: EngineSquared/EngineSquared
Length of output: 98
🏁 Script executed:
# Find the exact location of temporaryComponent definition
rg -n "temporaryComponent\s*=" src/engine/src/entity/EntityId.hppRepository: EngineSquared/EngineSquared
Length of output: 182
🏁 Script executed:
# Check if these functions are called from multiple threads or async contexts
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/ --type cpp --type hpp -A 2 -B 2Repository: EngineSquared/EngineSquared
Length of output: 98
🏁 Script executed:
# Check if there are any threading primitives used anywhere in the Core or Engine
rg -n "std::thread|std::async|\.spawn|std::mutex" src/engine/src/ -cRepository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Try searching for function calls without type specification
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/ -A 2 -B 2Repository: EngineSquared/EngineSquared
Length of output: 4821
🏁 Script executed:
# Check for threading usage more broadly
rg -n "std::thread|std::async|spawn" src/engine/src/Repository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Check if the Core class uses multithreading or async operations
rg -n "class Core|struct Core" src/engine/src/core/ -A 20Repository: EngineSquared/EngineSquared
Length of output: 2301
🏁 Script executed:
# Check if the scheduler system uses threading
rg -n "Scheduler|scheduler" src/engine/src/core/ -A 5 | head -100Repository: EngineSquared/EngineSquared
Length of output: 6465
🏁 Script executed:
# Check for any system that might process entities concurrently
rg -n "RemoveTemporaryComponents" src/engine/src/core/ -B 5 -A 5Repository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Let's see the complete picture of when temporaryComponent is accessed
rg -n "temporaryComponent" src/engine/src/ -B 2 -A 2Repository: EngineSquared/EngineSquared
Length of output: 1838
🏁 Script executed:
# Check if there are any async operations or threading in schedulers
rg -n "async|thread|concurrent|parallel" src/engine/src/scheduler/ -iRepository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Check the main application loop to see if multiple threads could call these functions
rg -n "AddTemporaryComponent|RemoveTemporaryComponents" src/engine/src/core/Core.cpp -A 3 -B 3Repository: EngineSquared/EngineSquared
Length of output: 53
🏁 Script executed:
# Look for plugin or system execution that might be multithreaded
find src/engine/src -name "*.cpp" -o -name "*.hpp" | xargs grep -l "AddTemporaryComponent\|RemoveTemporaryComponents"Repository: EngineSquared/EngineSquared
Length of output: 171
Protect temporaryComponent access with synchronization (data race / UB).
Lines 47-53 mutate the shared static map with a check-then-act pattern while lines 86-91 iterate and clear it with no synchronization. The TOCTOU window at line 47-49 and concurrent modification between iteration and clear create data races if called concurrently.
🔧 Suggested fix+#include <mutex>
+
namespace Engine {
+namespace {
+std::mutex temporaryComponentMutex;
+}
+
template <typename TTempComponent, typename... TArgs>
decltype(auto) EntityId::AddTemporaryComponent(Engine::Core &core, TArgs &&...args)
{
- if (!temporaryComponent.contains(std::type_index(typeid(TTempComponent))))
- {
- temporaryComponent[std::type_index(typeid(TTempComponent))] = [](Core &c) {
+ {
+ std::lock_guard<std::mutex> lock(temporaryComponentMutex);
+ temporaryComponent.try_emplace(std::type_index(typeid(TTempComponent)), [](Core &c) {
Log::Debug(fmt::format("RemoveTemporaryComponent: {}", typeid(TTempComponent).name()));
c.GetRegistry().clear<TTempComponent>();
- };
+ });
}
return this->AddComponent<TTempComponent>(core, std::forward<TArgs>(args)...);
}
@@
inline void EntityId::RemoveTemporaryComponents(Core &core)
{
- if (temporaryComponent.empty())
- {
- return;
- }
- for (const auto &[typeIndex, func] : temporaryComponent)
+ std::unordered_map<std::type_index, std::function<void(Core &)>> cleanupFns;
+ {
+ std::lock_guard<std::mutex> lock(temporaryComponentMutex);
+ if (temporaryComponent.empty())
+ {
+ return;
+ }
+ cleanupFns = temporaryComponent;
+ temporaryComponent.clear();
+ }
+ for (const auto &[typeIndex, func] : cleanupFns)
{
func(core);
}
- temporaryComponent.clear();
}Also applies to: 80-91
🤖 Prompt for AI AgentsVerify each finding against the current code and only fix it if needed. In `@src/engine/src/entity/EntityId.ipp` around lines 45 - 53, The shared static map temporaryComponent is accessed without synchronization in EntityId::AddTemporaryComponent and where it's iterated/cleared (lines ~86-91), creating TOCTOU and concurrent-modification races; fix by introducing a dedicated mutex (e.g., temporaryComponentMutex) and acquire a lock (std::lock_guard or std::scoped_lock) around all accesses and mutations of temporaryComponent, and replace the separate contains-then-assign pattern in AddTemporaryComponent with an atomic insert/emplace that uses the insertion result while still holding the lock to avoid race windows.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agentsVerify each finding against the current code and only fix it if needed. Inline comments: In `@src/engine/src/entity/Entity.cpp`: - Line 15: The method Entity::RemoveTemporaryComponents currently calls EntityId::RemoveTemporaryComponents(core) directly which bypasses the instance's context; change it to delegate via the wrapped id and context by invoking _entityId.RemoveTemporaryComponents(GetCore()) so it uses this Entity's stored _entityId and GetCore() rather than an arbitrary Core passed by callers. - Around line 17-19: The equality operators on Entity currently only compare _entityId.value; update both Entity::operator==(const Entity &rhs) and Entity::operator==(const EntityId &rhs) to include Core identity by delegating to EntityId's own operator== (or by comparing both _core and _entityId) instead of only comparing _entityId.value — i.e., use _entityId == rhs._entityId (or _entityId == rhs) and ensure the comparison accounts for the Core pointer/identifier so entities from different cores are not considered equal.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 58695a9c-6ad1-4c7a-ad21-4c5171ae1510
📥 CommitsReviewing files that changed from the base of the PR and between 9666d32 and 9ccfd9a.
📒 Files selected for processing (2)
Sorry, something went wrong.
|
|
||
| Entity::operator EntityId() const { return _entityId; } | ||
|
|
||
| void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟠 Major
RemoveTemporaryComponents bypasses the entity instance context.
This implementation ignores both _entityId and GetCore(), so callers can pass an unrelated Core. Delegate through the wrapped id/context like the rest of Entity APIs.
Proposed fix-void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); }
+void Entity::RemoveTemporaryComponents(Core &core) { _entityId.RemoveTemporaryComponents(core); }‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| void Entity::RemoveTemporaryComponents(Core &core) { EntityId::RemoveTemporaryComponents(core); } | |
| void Entity::RemoveTemporaryComponents(Core &core) { _entityId.RemoveTemporaryComponents(core); } |
Verify each finding against the current code and only fix it if needed. In `@src/engine/src/entity/Entity.cpp` at line 15, The method Entity::RemoveTemporaryComponents currently calls EntityId::RemoveTemporaryComponents(core) directly which bypasses the instance's context; change it to delegate via the wrapped id and context by invoking _entityId.RemoveTemporaryComponents(GetCore()) so it uses this Entity's stored _entityId and GetCore() rather than an arbitrary Core passed by callers.
Sorry, something went wrong.
| bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; } | ||
|
|
||
| bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; } |
There was a problem hiding this comment.
⚠️ Potential issue | 🟠 Major
Entity equality should include Core identity.
Comparing only EntityId.value can mark entities from different Core instances as equal. Compare both core identity and EntityId via its own operator.
Proposed fix-bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; }
+bool Entity::operator==(const Entity &rhs) const
+{
+ return &GetCore() == &rhs.GetCore() && _entityId == rhs._entityId;
+}
-bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; }
+bool Entity::operator==(const EntityId &rhs) const { return _entityId == rhs; }‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| bool Entity::operator==(const Entity &rhs) const { return _entityId.value == rhs._entityId.value; } | |
| bool Entity::operator==(const EntityId &rhs) const { return _entityId.value == rhs.value; } | |
| bool Entity::operator==(const Entity &rhs) const | |
| { | |
| return &GetCore() == &rhs.GetCore() && _entityId == rhs._entityId; | |
| } | |
| bool Entity::operator==(const EntityId &rhs) const { return _entityId == rhs; } |
Verify each finding against the current code and only fix it if needed. In `@src/engine/src/entity/Entity.cpp` around lines 17 - 19, The equality operators on Entity currently only compare _entityId.value; update both Entity::operator==(const Entity &rhs) and Entity::operator==(const EntityId &rhs) to include Core identity by delegating to EntityId's own operator== (or by comparing both _core and _entityId) instead of only comparing _entityId.value — i.e., use _entityId == rhs._entityId (or _entityId == rhs) and ensure the comparison accounts for the Core pointer/identifier so entities from different cores are not considered equal.
Sorry, something went wrong.
|
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Pull Request
Description
I included inside wiki (contributing) what kind of file we should put implementations and fixed it inside core.
Related Issues (Put "None" if there are no related issues)
close #526
Type of Change
Please delete options that are not relevant.
Changes Made
List the main changes in this PR:
Testing
Describe the tests you ran to verify your changes. Please delete options that are not relevant.
Test Environment
Screenshots/Videos (Put "None" if there are no related issues)
None
Documentation
Please delete options that are not relevant.
Checklist (Don't delete any options)
Breaking Changes (Put "None" if there are no related issues)
None
Additional Notes (Put "None" if there are no related issues)
None
Summary by CodeRabbit
Refactor
New Features
Style