1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 // #SchematycTODO : Inline helper structs and move to .cpp?
4 // #SchematycTODO : Sort slots by scope address?
8 #include <CrySchematyc2/Services/IUpdateScheduler.h>
9 #include <ILevelSystem.h>
12 #define DEBUG_RELEVANCE_GRID (1)
13 #define DEBUG_BUCKETS_NAMES (1)
18 class CUpdateScheduler
;
20 // A simple grid implementation, which is connecting/disconnecting schematyc component updates based on relevant entities (players)
22 : public ISystemEventListener
23 , public ILevelSystemListener
26 enum ECellChangedResult
28 eCellChangedResult_Same
,
29 eCellChangedResult_Changed
,
30 eCellChangedResult_NotFound
,
31 eCellChangedResult_Count
34 // Stores all the info needed to hook a update callback from schematyc components
35 struct SUpdateCallback
37 SUpdateCallback(CUpdateScope
* pScope
, const UpdateCallback
& callback
, UpdateFrequency frequency
, UpdatePriority priority
, const UpdateFilter
& filter
);
40 UpdateCallback callback
;
41 UpdateFrequency frequency
;
42 UpdatePriority priority
;
46 typedef std::vector
<SUpdateCallback
> TUpdateCallbacks
;
48 // Add more information here in case we need better filtering for dynamic objects
51 SDynamicObject(CUpdateScope
* pScope
, const UpdateCallback
& callback
, UpdateFrequency frequency
, UpdatePriority priority
, const UpdateFilter
& filter
);
53 SUpdateCallback updateCallback
;
56 typedef std::vector
<SDynamicObject
> TDynamicObjects
;
64 TUpdateCallbacks globalUpdateCallbacks
;
65 TUpdateCallbacks localGridUpdateCallbacks
;
66 short relevanceCounter
;
69 typedef std::vector
<SGridCell
> TGridCells
;
77 , id(INVALID_ENTITYID
)
81 SRelevantCell(ushort x
, ushort y
, ushort cellIdx
, EntityId id
, bool bIsLocal
)
96 typedef std::vector
<SRelevantCell
> TRelevantCells
;
100 virtual ~CRelevanceGrid();
102 // ISystemEventListener
103 virtual void OnSystemEvent(ESystemEvent event
, UINT_PTR wparam
, UINT_PTR lparam
) override
;
104 // ~ISystemEventListener
106 // ILevelSystemListener
107 virtual void OnLoadingLevelEntitiesStart(ILevelInfo
* pLevel
) override
;
108 // ~ILevelSystemListener
110 bool Register(CUpdateScope
* pScope
, const UpdateCallback
& callback
, UpdateFrequency frequency
, UpdatePriority priority
, const UpdateFilter
& filter
);
111 void Unregister(CUpdateScope
* pScope
);
112 bool RegisterDynamicObject(CUpdateScope
* pScope
, const UpdateCallback
& callback
, UpdateFrequency frequency
, UpdatePriority priority
, const UpdateFilter
& filter
);
113 void UnregisterDynamicObject(CUpdateScope
* pScope
);
114 void Update(CUpdateRelevanceContext
* pRelevanceContext
= nullptr);
115 void SetUpdateScheduler(CUpdateScheduler
* pScheduler
);
119 void SetupUpdateCallbacksAroundCell(ushort cellX
, ushort cellY
, bool bIsLocal
, bool bConnect
);
120 void ConnectCell(ushort idx
, bool bIsLocal
);
121 void DisconnectCell(ushort idx
, bool bIsLocal
);
122 ECellChangedResult
DidRelevantCellIndexChange(const SRelevantCell
& cellToFind
, SRelevantCell
*& pCellInfo
);
123 void GetCellCoordinates(const Vec3 worldPos
, ushort
&x
, ushort
& y
, ushort
& cellIdx
) const;
124 ushort
GetCellIndex(ushort x
, ushort y
) const;
126 #if DEBUG_RELEVANCE_GRID
127 void DebugDrawStatic(CUpdateRelevanceContext
* pRelevanceContext
);
128 void DebugLogStaticMemoryStats();
133 TDynamicObjects m_dynamicObjects
;
134 TRelevantCells m_relevantCells
;
135 CUpdateScheduler
* m_pUpdateScheduler
;
136 std::vector
<Vec3
> m_relevantEntitiesWorldPos
;
137 int m_gridSize
; // The grid size. Its a square so m_gridSize x m_gridSize
138 int m_gridSizeMinusOne
; // Cached constantly needed value
139 int m_updateHalfDistance
; // The update distance around the relevant cells in cells (e.g. 1, 2... cells)
141 #if DEBUG_RELEVANCE_GRID
142 int m_debugUpdateFrame
;
146 class CUpdateScheduler
: public IUpdateScheduler
148 friend class CRelevanceGrid
;
157 virtual bool Connect(CUpdateScope
& scope
, const UpdateCallback
& callback
, UpdateFrequency frequency
= EUpdateFrequency::EveryFrame
, UpdatePriority priority
= EUpdatePriority::Default
, const UpdateFilter
& filter
= UpdateFilter()) override
;
158 virtual void Disconnect(CUpdateScope
& scope
) override
;
159 virtual bool InFrame() const override
;
160 virtual bool BeginFrame(float frameTime
) override
;
161 virtual bool Update(UpdatePriority beginPriority
= EUpdateStage::PrePhysics
| EUpdateDistribution::Earliest
, UpdatePriority endPriority
= EUpdateStage::Post
| EUpdateDistribution::End
, CUpdateRelevanceContext
* pRelevanceContext
= nullptr) override
;
162 virtual bool EndFrame() override
;
163 virtual void VerifyCleanup() override
;
164 virtual void Reset() override
;
165 virtual const UpdateSchedulerStats::IFrameUpdateStats
* GetFrameUpdateStats() const override
;
166 virtual void SetShouldUseRelevanceGridCallback(UseRelevanceGridPredicate directConnect
) override
;
167 virtual void SetIsDynamicObjectCallback(IsDynamicObjectPredicate isDynamicObject
) override
;
168 virtual void SetDebugPriorityNames(const DebugPriorityNameArray
& debugNames
) override
;
173 bool ConnectInternal(CUpdateScope
& scope
, const UpdateCallback
& callback
, UpdateFrequency frequency
= EUpdateFrequency::EveryFrame
, UpdatePriority priority
= EUpdatePriority::Default
, const UpdateFilter
& filter
= UpdateFilter());
174 void DisconnectInternal(CUpdateScope
&scope
);
175 void UnregisterFromRelevanceGrid(CUpdateScope
& scope
);
180 SUpdateSlot(const UpdatePriority priority
, const UpdateFrequency frequency
);
182 UpdatePriority priority
;
183 UpdateFrequency bucketIndex
;
185 inline bool operator <(const SUpdateSlot
& rhs
) const
187 return priority
> rhs
.priority
;
191 typedef std::vector
<SUpdateSlot
> TUpdateSlots
;
196 SObserver(CUpdateScope
& scope
, const UpdateCallback
& callback
, const UpdateFilter
& filter
, UpdateFrequency frequency
, UpdateFrequency stride
);
198 CUpdateScope
* pScope
;
199 UpdateCallback callback
;
201 UpdateFrequency frequency
: 8;
202 UpdateFrequency stride
: 8;
204 static_assert(sizeof(UpdateFrequency
) == 2, "UpdateFrequency expected to be 16 bit");
207 typedef std::vector
<SObserver
> TObserverVector
;
209 struct SPendingObserver
: public SObserver
212 SPendingObserver(CUpdateScope
& scope
, const UpdateCallback
& callback
, const UpdateFilter
& filter
, UpdateFrequency frequency
, UpdateFrequency stride
, UpdatePriority priority
);
214 UpdatePriority priority
;
217 struct SFrameUpdateStats
: public UpdateSchedulerStats::IFrameUpdateStats
219 enum { k_maxStagesCount
= 8 };
220 enum { k_maxBucketsCount
= EUpdateFrequency::Count
};
224 void Add(const UpdateSchedulerStats::SUpdateStageStats
& stats
);
225 void AddConnected(int64 timeTicks
);
226 void AddDisconnected(int64 timeTicks
);
229 virtual const UpdateSchedulerStats::SUpdateStageStats
* GetStageStats(size_t& outCount
) const override
;
230 virtual const UpdateSchedulerStats::SUpdateBucketStats
* GetBucketStats(size_t& outCount
) const override
;
231 virtual const UpdateSchedulerStats::SChangeStats
* GetChangeStats() const override
{ return &changeStats
; }
233 UpdateSchedulerStats::SUpdateStageStats stagesStats
[k_maxStagesCount
];
235 UpdateSchedulerStats::SUpdateBucketStats bucketStats
[k_maxBucketsCount
];
236 UpdateSchedulerStats::SChangeStats changeStats
;
239 typedef std::vector
<size_t> TDirtyIndicesVector
;
241 struct SObserverGroup
245 TObserverVector observers
;
246 TDirtyIndicesVector dirtyIndices
;
249 typedef VectorMap
<UpdatePriority
, SObserverGroup
> TObserverMap
;
250 typedef std::vector
<SPendingObserver
> TPendingObservers
;
251 typedef std::vector
<UpdatePriority
> TPendingPriorities
;
252 typedef VectorMap
<UpdatePriority
, const char*> TPriorityDebugNameMap
;
261 void Connect(CUpdateScope
& scope
, const UpdateCallback
& callback
, UpdateFrequency frequency
, UpdatePriority priority
, const UpdateFilter
& filter
);
262 void Disconnect(CUpdateScope
& scope
, UpdatePriority priority
);
263 void BeginUpdate(TPendingPriorities
& pendingPriorities
);
264 template <bool UseStride
>
265 void Update(const SUpdateContext context
, UpdatePriority priority
, uint32 frameId
, UpdateSchedulerStats::SUpdateBucketStats
& outUpdateStats
, const TPriorityDebugNameMap
& debugNames
);
268 void SetFrequency(UpdateFrequency frequency
);
271 UpdateFrequency
SelectNewStride() const;
272 void AddObserver(TObserverVector
& observers
, CUpdateScope
& scope
, const UpdateCallback
& callback
, const UpdateFilter
& filter
);
273 void DeleteDirtyObservers();
274 void AddPendingObservers(TPendingPriorities
& pendingPriorities
);
275 const char* GetDebugName(UpdatePriority priority
, const TPriorityDebugNameMap
& debugNames
);
279 TObserverMap m_observers
;
280 TPendingObservers m_pendingNewPriorityObservers
;
281 size_t m_totalObserverCount
;
282 size_t m_totalDirtyCount
;
283 std::vector
<size_t> m_frameStrideBuckets
;
284 UpdateFrequency m_frequency
;
287 static const size_t s_maxFrameStride
= 1 << (EUpdateFrequency::Count
- 1);
290 CBucket m_buckets
[EUpdateFrequency::Count
];
291 TUpdateSlots m_updateOrder
;
292 size_t m_updatePosition
;
293 float m_frameTimes
[s_maxFrameStride
];
297 TPriorityDebugNameMap m_debugNameMap
;
298 SFrameUpdateStats m_stats
;
299 TPendingPriorities m_pendingPriorities
;
300 // Relevance grid related members
301 CRelevanceGrid m_relevanceGrid
;
302 IUpdateScheduler::UseRelevanceGridPredicate m_useRelevanceGrid
;
303 IUpdateScheduler::IsDynamicObjectPredicate m_isDynamicObject
;