System group allocator
Each ComponentSystemGroup
has an option to create a system group allocator when setting its rate manager. To do this, use ComponentSystemGroup.SetRateManagerCreateAllocator
. If you use the property RateManager
to set a rate manager in the system group, then component system group doesn't create a system group allocator.
The following example uses ComponentSystemGroup.SetRateManagerCreateAllocator
to set a rate manager and create a system group allocator:
[WorldSystemFilter(WorldSystemFilterFlags.Default | WorldSystemFilterFlags.Editor | WorldSystemFilterFlags.ThinClientSimulation)]
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup), OrderFirst = true)]
public partial class FixedStepTestSimulationSystemGroup : ComponentSystemGroup
{
// Set the timestep use by this group, in seconds. The default value is 1/60 seconds.
// This value will be clamped to the range [0.0001f ... 10.0f].
public float Timestep
{
get => RateManager != null ? RateManager.Timestep : 0;
set
{
if (RateManager != null)
RateManager.Timestep = value;
}
}
// Default constructor
public FixedStepTestSimulationSystemGroup()
{
float defaultFixedTimestep = 1.0f / 60.0f;
// Set FixedRateSimpleManager to be the rate manager and create a system group allocator
SetRateManagerCreateAllocator(new RateUtils.FixedRateSimpleManager(defaultFixedTimestep));
}
}
The component system group that creates a system group allocator contains double rewindable allocators. World.SetGroupAllocator
and World.RestoreGroupAllocator
are used in IRateManager.ShouldGroupUpdate
to replace the world update allocator with the system group allocator, and later to restore back the world update allocator.
The example below shows how to use World.SetGroupAllocator
and World.RestoreGroupAllocator
:
public unsafe class FixedRateSimpleManager : IRateManager
{
const float MinFixedDeltaTime = 0.0001f;
const float MaxFixedDeltaTime = 10.0f;
float m_FixedTimestep;
public float Timestep
{
get => m_FixedTimestep;
set => m_FixedTimestep = math.clamp(value, MinFixedDeltaTime, MaxFixedDeltaTime);
}
double m_LastFixedUpdateTime;
bool m_DidPushTime;
DoubleRewindableAllocators* m_OldGroupAllocators = null;
public FixedRateSimpleManager(float fixedDeltaTime)
{
Timestep = fixedDeltaTime;
}
public bool ShouldGroupUpdate(ComponentSystemGroup group)
{
// if this is true, means we're being called a second or later time in a loop.
if (m_DidPushTime)
{
group.World.PopTime();
m_DidPushTime = false;
// Update the group allocators and restore the old allocator
group.World.RestoreGroupAllocator(m_OldGroupAllocators);
return false;
}
group.World.PushTime(new TimeData(
elapsedTime: m_LastFixedUpdateTime,
deltaTime: m_FixedTimestep));
m_LastFixedUpdateTime += m_FixedTimestep;
m_DidPushTime = true;
// Back up current world or group allocator.
m_OldGroupAllocators = group.World.CurrentGroupAllocators;
// Replace current world or group allocator with this system group allocator.
group.World.SetGroupAllocator(group.RateGroupAllocators);
return true;
}
}
The system group allocator contains double rewindable allocators and works in the same way as the world update allocator. Before a system group proceeds to its update, its system group allocator is put in the world update allocator, and allocations from the world update allocator are allocated from the system group allocator.
If the system group skips its update, it switches the double rewindable allocators of the system group allocator, rewinds the one that swaps in, and then brings back the world update allocator. Because this is a double rewindable allocator, the lifetime of an allocation from a system group allocator lasts two system group updates. You don't need to manually free the allocations, so there isn't any memory leakage.
In the example below, the system group allocator is used in ExampleSystemGroupAllocatorSystem
which is in a fixed rate system group that has a rate manager FixedRateSimpleManager
as shown above.
// Access world update allocator through SystemState.WorldUpdateAllocator.
unsafe partial struct AllocateNativeArrayISystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
// Get world update allocator through SystemState.WorldUpdateAllocator.
var allocator = state.WorldUpdateAllocator;
// Create a native array using world update allocator.
var nativeArray = CollectionHelper.CreateNativeArray<int>(10, allocator);
for (int i = 0; i < 10; i++)
{
nativeArray[i] = i;
}
}
}