Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughVisibility, ownership, and virtual-world handling moved from direct Streamable fields to ECS tag components and relation-based APIs; server/client GUID/ServerID caches added via observers; streaming/emitter logic refactored to use prefabs, iterator-based loops, and component-driven spawn/despawn semantics. Changes
Sequence Diagram(s)sequenceDiagram
participant Server as ServerEngine
participant World as Engine
participant Client as ClientEngine
participant Net as Network
Server->>World: Query entities (AlwaysVisible / Normal)
World-->>Server: Return entities + VirtualWorld / OwnedBy relations
Server->>Server: Evaluate visibility (Hidden/AlwaysVisible/VirtualWorld/Distance/Replace tags)
Server->>World: Add/Remove `StreamedTo` relations (spawn/despawn)
Server->>Net: Send GameSyncEntityUpdate (spawn/update/despawn)
Net->>Client: Deliver GameSyncEntityUpdate
Client->>Client: Lookup entity via _serverIdCache
Client->>World: Request virtual-world or entity resolution if needed
World-->>Client: Provide virtual-world/entity info
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
code/framework/src/world/server.cpp (1)
186-203: ApplyNoTickUpdatesto owner updates too.
The tag is documented as disabling tick updates, but the owner-update path still fires, so owned entities will still send updates when tagged.🛠️ Suggested fix
- if (otherS.GetBaseEvents().ownerUpdateProc) + if (otherS.GetBaseEvents().ownerUpdateProc && !e.has<Modules::Base::NoTickUpdates>()) otherS.GetBaseEvents().ownerUpdateProc(_networkPeer, s[i].guid, e);
🤖 Fix all issues with AI agents
In `@code/framework/src/world/client.cpp`:
- Around line 24-35: The cache population fails because CreateEntity uses
e.ensure<Modules::Base::ServerID>() and then writes sid.id directly, which
doesn't fire the OnSet observer registered in ServerIDCacheUpdate; after
assigning sid.id = serverID in CreateEntity, call
e.modified<Modules::Base::ServerID>() to trigger the observer so _serverIdCache
is updated (this ensures GetEntityByServerID() can find new entities); keep the
existing ServerIDCacheUpdate and ServerIDCacheRemove observers unchanged.
In `@code/framework/src/world/server.cpp`:
- Around line 256-275: SetOwnerRelation currently removes the OwnedBy relation
but doesn't clear the stored owner GUID on the component, leaving
Streamable.owner stale and GetOwner() able to resolve the old owner; update
ServerEngine::SetOwnerRelation so that when owner is invalid or ownership is
being removed it also resets/clears the Streamable::owner GUID (or related owner
field) on entity e (use the same path you use to set it when adding ownership),
ensuring GetOwnerRelation/GetOwner return null after removal; touch the same
symbols Modules::Base::OwnedBy, ServerEngine::SetOwnerRelation, and
Streamable::owner (or the component that stores the owner GUID) so the GUID is
cleared when e.remove<Modules::Base::OwnedBy>(...) is called.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@code/framework/src/world/types/streaming.hpp`:
- Around line 18-25: The SetupDefaults function updates
streamable.defaultUpdateInterval but leaves streamable.updateInterval stale; in
SetupDefaults (function SetupDefaults, struct
Framework::World::Modules::Base::Streamable) set streamable.updateInterval =
streamable.defaultUpdateInterval (ensure units are ms as done for
defaultUpdateInterval) so newly created entities inherit the current tick-rate
cadence rather than the prefab's old value.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@code/framework/src/world/server.cpp`:
- Around line 39-53: The OnAdd observer that handles Modules::Base::OwnedBy
updates Streamable->owner but there is no OnRemove counterpart, so
Streamable.owner remains stale when ownership is cleared; add an OnRemove
observer on _world->observer() with Modules::Base::OwnedBy (flecs::Wildcard) and
in its each lambda locate the entity (same e),
get_mut<Modules::Base::Streamable>() and if present clear streamable->owner
(e.g. set to invalid/zero GUID) whenever the owner relation is removed (covers
removals from SetOwnerRelation and direct removals) so GetOwner() no longer
returns stale GUIDs.
- Around line 55-76: The SpawnObserver currently listens for flecs::OnSet which
fires on both additions and modifications; change the observer for
"SpawnObserver" that uses
.with<Modules::Base::StreamedTo>(flecs::Wildcard).event(flecs::OnSet) to use
.event(flecs::OnAdd) instead so spawn RPCs are only sent when the StreamedTo
relation is added (leave the rest of the lambda body—entity lookup, streamer
retrieval, Transform handling, SetServerID and Send—unchanged).
🧹 Nitpick comments (1)
code/framework/src/world/server.cpp (1)
112-137: Consider whetherSetOwnerRelationshould be used here for consistency.The system directly sets
streamable.ownerwithout establishing theOwnedByrelation. This means entities assigned ownership through this automatic system won't have the relation-based ownership thatSetOwnerRelationprovides.This may be intentional (keeping automatic GUID-based ownership separate from explicit relation-based ownership), but worth confirming the design intent.
Summary
Modernize ECS usage by replacing legacy patterns with proper Flecs features: zero-size tags, observer-maintained caches, entity relations, and observer-based event handling.
Changes
Tags replace boolean fields:
Hiddentag replacesisVisiblefield (inverted logic)AlwaysVisibletag replacesalwaysVisiblefieldNoTickUpdatestag replacesperformTickUpdatesfield (inverted logic)ManualOwnershiptag replacesassignOwnerManuallyfieldVisibilityReplaceandVisibilityReplacePositiontags replaceHeuristicModeenumZero-size marker components:
PendingRemovalandRemovedOnResourceReloadconverted to proper zero-size tagsO(1) entity lookups:
EngineClientEngineRelations:
OwnedByrelation for entity-to-entity ownership modelingStreamedTorelation tracks which entities are streamed to which playersInVirtualWorldrelation for virtual world membershipOwnedByrelation toownerGUID field for network compatibilityObserver-based event system (replaces callback injection):
SpawnObserver: SendsGameSyncEntitySpawnwhenStreamedTorelation is addedDespawnObserver: SendsGameSyncEntityDespawnwhenStreamedTorelation is removedStreamEntitiessystem based on ownership and intervalsSetupServerEmitters()andSetupClientEmitters()- no longer neededStreamable.Eventsstruct and all callback procsVirtual world system:
VirtualWorldcomponent marks world entitiesInVirtualWorldrelation for entity world membershipGetOrCreateVirtualWorld(),SetEntityVirtualWorld(),GetEntityVirtualWorld(),AreInSameVirtualWorld()Entity prefabs:
StreamableEntityPrefabwith Transform, Streamable, TickRateRegulatorStreamerEntityPrefabinheriting from StreamableEntityPrefab, adds Streamere.is_a(Prefab)for efficient component allocationDecomposed visibility system:
_alwaysVisibleEntitiesquery: pre-filtered for AlwaysVisible entities (skip distance check)_normalStreamableEntitiesquery: pre-filtered for normal entities (full visibility check).with<>()and.without<>()instead of runtime checksBreaking Changes
Removed from
Streamablecomponent:bool isVisible→ useHiddentagbool alwaysVisible→ useAlwaysVisibletagbool performTickUpdates→ useNoTickUpdatestagbool assignOwnerManually→ useManualOwnershiptagenum HeuristicModeandisVisibleHeuristic→ useVisibilityReplace/VisibilityReplacePositiontagsEventsstruct (spawnProc,despawnProc,updateProc, etc.) → framework handles via observersmodEvents→ use Flecs observers onStreamedTorelation for custom behaviorRemoved from
Streamercomponent:std::unordered_map<flecs::entity_t, StreamData> entities→ replaced byStreamedTorelationRemoved functions:
Modules::Base::SetupServerEmitters()Modules::Base::SetupClientEmitters()Migration Guide
Benefits
Test Plan
SetVisible,IsVisible,SetAlwaysVisible,SetVirtualWorld, etc.)