I have a static factory method that creates an entity with some components. It’s overloaded: one method takes in EntityCommandBuffer while the other takes in a EntityCommandBuffer.Concurrent and an index. The concurrent one works fine and produces a valid entity with the components. However, the sequential one is producing an entity with a negative index and a zeroed version! Here are the factory methods
public static class MessageFactory
{
public static Entity CreateDelayedMessage(
EntityCommandBuffer ecb,
Entity sender,
Entity receiver,
float secondsToWait
)
{
var newMessage = ecb.CreateEntity();
ecb.AddComponent(newMessage, new MessageReceiver
{
receiver = receiver
});
ecb.AddComponent(newMessage, new MessageSender
{
sender = sender
});
ecb.AddComponent(newMessage, new WaitStartMessage
{
secondsToWait = secondsToWait
});
return newMessage;
}
public static Entity CreateDelayedMessage(
EntityCommandBuffer.Concurrent ecb,
int jobIndex,
Entity sender,
Entity receiver,
float secondsToWait
)
{
var newMessage = ecb.CreateEntity(jobIndex);
ecb.AddComponent(jobIndex,newMessage, new MessageReceiver
{
receiver = receiver
});
ecb.AddComponent(jobIndex,newMessage, new MessageSender
{
sender = sender
});
ecb.AddComponent(jobIndex,newMessage, new WaitStartMessage
{
secondsToWait = secondsToWait
});
return newMessage;
}
}
And here is the job, which is scheduled sequentially (ScheduleSingle)
private struct ReceiveCommunicationJob : IJobForEachWithEntity<AttackingCommunicationWaiter, WaitCompleteMessage,MessageReceiver, MessageSender>
{
public EntityCommandBuffer ecb;
public BufferFromEntity<AttackingCommunicatedAlliesElement> communicatedAlliesFromEntity;
public ComponentDataFromEntity<BlackboardType> blackboardFromEntity;
public ComponentDataFromEntity<GlobalAttackingBlackboard> globalBlackboardFromEntity;
public ComponentDataFromEntity<AttackingCommunication> communicationFromEntity;
public BufferFromEntity<AttackingCommunicationTrackedWaiterElement> trackedWaitersFromEntity;
public BufferFromEntity<AllyWithinSpeakingRangeElement> speakingRangeAlliesFromEntity;
public void Execute(
Entity waiterEntity,
int index,
[ReadOnly] ref AttackingCommunicationWaiter waiter,
[ReadOnly] ref WaitCompleteMessage finishedMessage,
[ReadOnly] ref MessageReceiver receiver,
[ReadOnly] ref MessageSender sender
)
{
var recipientEntity = receiver.receiver;
var recipientBlackboard = blackboardFromEntity[recipientEntity];
var recipientBlackboardData = recipientBlackboard.GetBlackboard();
var senderEntity = sender.sender;
var senderBlackboard = blackboardFromEntity[senderEntity];
var senderBlackboardData = senderBlackboard.GetBlackboard();
if (senderBlackboardData.FresherThen(recipientBlackboardData))
{
recipientBlackboardData.ReplaceWith(senderBlackboardData);
}
recipientBlackboard.SetBlackboard(recipientBlackboardData);
blackboardFromEntity[recipientEntity] = recipientBlackboard;
var recipientGlobalBlackboardData = globalBlackboardFromEntity[recipientEntity];
var senderGlobalBlackboardData = globalBlackboardFromEntity[senderEntity];
if (senderGlobalBlackboardData.FresherThen(recipientGlobalBlackboardData))
{
recipientGlobalBlackboardData.ReplaceWith(recipientGlobalBlackboardData);
}
globalBlackboardFromEntity[recipientEntity] = recipientGlobalBlackboardData;
var trackerEntity = waiter.tracker;
var trackedWaiters = trackedWaitersFromEntity[trackerEntity];
Debug.Log("Before: " + trackedWaiters.Length);
for(int i = 0; i < trackedWaiters.Length; i++)
{
Debug.Log("Current waiters: " + trackedWaiters[i].waiter.ToString());
}
trackedWaiters.Remove(new AttackingCommunicationTrackedWaiterElement
{
waiter = waiterEntity
});
Debug.Log(trackedWaiters.Length + " due to removing: " + waiterEntity.ToString());
var communicatedAllies = communicatedAlliesFromEntity[trackerEntity];
var recipientCommunicator = communicationFromEntity[recipientEntity];
var alliesWithinSpeakingRange = speakingRangeAlliesFromEntity[recipientEntity];
var numAlliesWithinSpeakingRange = alliesWithinSpeakingRange.Length;
for (var i = 0; i < numAlliesWithinSpeakingRange; i++)
{
var ally = alliesWithinSpeakingRange[i].entity;
if(communicatedAllies.Contains(new AttackingCommunicatedAlliesElement
{
ally = ally
}))
{
continue;
}
communicatedAllies.Add(new AttackingCommunicatedAlliesElement
{
ally = ally
});
var newWaiter =
MessageFactory.CreateDelayedMessage(
ecb,
recipientEntity,
ally,
recipientCommunicator.verbalCommunicationTime
);
Debug.Log("New waiter: " + newWaiter.ToString());
ecb.AddComponent(newWaiter, new AttackingCommunicationWaiter
{
tracker = trackerEntity
});
ecb.AddComponent( newWaiter, recipientBlackboard);
ecb.AddComponent( newWaiter, recipientGlobalBlackboardData);
trackedWaiters.Add(new AttackingCommunicationTrackedWaiterElement
{
waiter = newWaiter
});
}
ecb.AddComponent( waiterEntity, new MessageFinished());
}
}
Here is the code that schedules the above job as well as related jobs. Note that the same EntityCommandBuffer is used across all three. Maybe that’s related to the problem?
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var ecb = endFrame.CreateCommandBuffer();
var ecbConcurrent = ecb.ToConcurrent();
var alliesFromEntity = GetBufferFromEntity<AllyWithinSpeakingRangeElement>(true);
var communicatedAlliesFromEntity = GetBufferFromEntity< AttackingCommunicatedAlliesElement>();
var blackboardFromEntity = GetComponentDataFromEntity< BlackboardType>();
var globalBlackboardFromEntity = GetComponentDataFromEntity<GlobalAttackingBlackboard>();
var communicationFromEntity = GetComponentDataFromEntity<AttackingCommunication>();
var trackedWaitersFromEntity = GetBufferFromEntity<AttackingCommunicationTrackedWaiterElement>();
var speakingRangeAlliesFromEntity = GetBufferFromEntity<AllyWithinSpeakingRangeElement>();
var trackedWaitersFromEntityReadonly = GetBufferFromEntity<AttackingCommunicationTrackedWaiterElement>(true);
inputDeps = new StartCommunicationJob
{
ecb = ecbConcurrent,
alliesFromEntity = alliesFromEntity
}.Schedule(this, inputDeps);
inputDeps = new ReceiveCommunicationJob
{
ecb = ecb,
communicationFromEntity = communicationFromEntity,
communicatedAlliesFromEntity = communicatedAlliesFromEntity,
blackboardFromEntity = blackboardFromEntity,
globalBlackboardFromEntity = globalBlackboardFromEntity,
trackedWaitersFromEntity = trackedWaitersFromEntity,
speakingRangeAlliesFromEntity = speakingRangeAlliesFromEntity
}.ScheduleSingle(this, inputDeps);
inputDeps = new EndCommunicationJob
{
trackedWaitersFromEntity = trackedWaitersFromEntityReadonly,
ecb = ecbConcurrent
}.Schedule(this, inputDeps);
endFrame.AddJobHandleForProducer(inputDeps);
return inputDeps;
}