I’d been using NativeMultiHashMap to gather together spell occurrences according by target entity, but I noticed that NativeMultiHashMap.ParallelWriter uses atomic operations, are atomic operations too bad in this case(assuming that it’ll be dozens of this systems running, one per each spell component) ? if it does, is there a better way to do it?
Job Structures
[BurstCompile]
[ExcludeComponent(typeof(SpellHeader))]
public struct GatherBreakingSpellJob : IJobForEachWithEntity<SpellState<TSpell, TTargetComponent>>
{
[WriteOnly]
public NativeMultiHashMap<Entity, SpellEntry>.ParallelWriter SpellEntries;
public void Execute(Entity Entity, int Index, ref SpellState<TSpell, TTargetComponent> SpellState)
{
SpellEntries.Add(SpellState.TargetEntity, new SpellEntry
{
Entity = Entity,
Spell = SpellState.Spell,
IsCasting = false
});
}
}
[BurstCompile]
public struct GatherCastingSpellJob : IJobForEachWithEntity<SpellHeader, TSpell>
{
[WriteOnly]
public NativeMultiHashMap<Entity, SpellEntry>.ParallelWriter SpellEntries;
public void Execute(Entity Entity, int Index, [ReadOnly] ref SpellHeader SpellHeader, [ReadOnly] ref TSpell SpellComponent)
{
SpellEntries.Add(SpellHeader.TargetEntity, new SpellEntry
{
Entity = Entity,
Spell = SpellComponent,
IsCasting = true
});
}
}
[BurstCompile]
public struct SpellJob : IJobNativeMultiHashMapVisitKeyValue<Entity, SpellEntry>
{
[NativeDisableParallelForRestriction]
public ComponentDataFromEntity<TTargetComponent> TargetComponentDataFromEntity;
[WriteOnly]
public EntityCommandBuffer.Concurrent EntityCommandBuffer;
[NativeSetThreadIndex]
int m_ThreadIndex;
public void ExecuteNext(Entity TargetEntity, SpellEntry SpellEntry)
{
bool IsCasting = SpellEntry.IsCasting;
if (!TargetComponentDataFromEntity.Exists(TargetEntity))
{
EntityCommandBuffer.DestroyEntity(m_ThreadIndex, SpellEntry.Entity);
if (!IsCasting)
{
EntityCommandBuffer.RemoveComponent(m_ThreadIndex, SpellEntry.Entity, typeof(SpellState<TSpell, TTargetComponent>));
}
return;
}
var TargetComponent = TargetComponentDataFromEntity[TargetEntity];
ref var Spell = ref SpellEntry.Spell;
if (IsCasting)
{
Spell.Cast(ref TargetComponent);
EntityCommandBuffer.AddComponent(m_ThreadIndex, SpellEntry.Entity, new SpellState<TSpell, TTargetComponent>
{
Spell = Spell,
TargetEntity = TargetEntity
});
}
else
{
Spell.Break(ref TargetComponent);
EntityCommandBuffer.RemoveComponent(m_ThreadIndex, SpellEntry.Entity, typeof(SpellState<TSpell, TTargetComponent>));
}
TargetComponentDataFromEntity[TargetEntity] = TargetComponent;
}
}