UMassAgentComponent will block by check.
create a AThirdFirstCharacter and default SetReplicates(true);
class AThirdFirstCharacter : public ACharacter
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Mass, meta = (AllowPrivateAccess = "true"))
class UMassAgentComponent* MassAgentComponent;
}
AThirdFirstCharacter::AThirdFirstCharacter()
{
SetReplicates(true);
MassAgentComponent = CreateDefaultSubobject<UMassAgentComponent>(TEXT("MassAgentComponent"));
}
Create a mass asset
Put mass asset to MassAgentComponent
run PIE As Client. client will match MASSAGENT_CHECK if exist game. the State is PuppetPendingReplication
void UMassAgentComponent::UnregisterWithAgentSubsystem()
{
if (State != EAgentComponentState::None)
{
if (UMassAgentSubsystem* AgentSubsystem = UWorld::GetSubsystem<UMassAgentSubsystem>(GetWorld()))
{
UE_VLOG(GetOwner(), LogMass, Verbose, TEXT("%s"), ANSI_TO_TCHAR(__FUNCTION__));
AgentSubsystem->ShutdownAgentComponent(*this);
MASSAGENT_CHECK(State == EAgentComponentState::None ||
State == EAgentComponentState::PuppetPaused ||
State == EAgentComponentState::PuppetReplicatedOrphan,
TEXT("%s is expecting to be in state[None|PuppetPaused|PuppetReplicatedOrphan] state but is in %s"), ANSI_TO_TCHAR(__FUNCTION__), *UEnum::GetValueAsString(State));
}
}
DebugCheckStateConsistency();
if (AgentHandle.IsValid())
{
ClearEntityHandleInternal();
}
State = EAgentComponentState::None;
TemplateID = FMassEntityTemplateID();
}
I check the engine code
CreationContext will run not execute FCreationContext::~FCreationContext() before AgentComponents[AgentIndex]->SetEntityHandle(Entities[AgentIndex]), but UMassAgentComponent::SetEntityHandle(const FMassEntityHandle NewHandle) will set NetID which will be sync to client.
So UMassAgentComponent::NetID will be 0 forever.
void UMassAgentSubsystem::HandlePendingInitialization()
{
check(EntityManager);
check(SpawnerSystem);
check(SimulationSystem);
check(SimulationSystem->IsDuringMassProcessing() == false);
{
// this block is scoped so that CreationContext gets released by the end
TSharedPtr<FMassEntityManager::FEntityCreationContext> CreationContext = EntityManager->GetOrMakeCreationContext();
for (TTuple<FMassEntityTemplateID, FMassAgentInitializationQueue>& Data : PendingAgentEntities)
{
const FMassEntityTemplateID EntityTemplateID = Data.Get<0>();
const TSharedRef<FMassEntityTemplate>* EntityTemplatePtr = SpawnerSystem->GetTemplateRegistryInstance().FindTemplateFromTemplateID(EntityTemplateID);
check(EntityTemplatePtr);
const FMassEntityTemplate& EntityTemplate = EntityTemplatePtr->Get();
TArray<TObjectPtr<UMassAgentComponent>>& AgentComponents = Data.Get<1>().AgentComponents;
const int32 NewEntityCount = AgentComponents.Num();
if (NewEntityCount <= 0)
{
// this case is perfectly fine, all agents registered and unregistered before we processed the queue
continue;
}
TArray<FMassEntityHandle> Entities;
CreationContext = SpawnerSystem->SpawnEntities(EntityTemplate, NewEntityCount, Entities);
check(Entities.Num() == NewEntityCount);
if (EntityTemplate.GetObjectFragmentInitializers().Num())
{
const TConstArrayView<FMassEntityTemplateData::FObjectFragmentInitializerFunction> ObjectFragmentInitializers = EntityTemplate.GetObjectFragmentInitializers();
for (int AgentIndex = 0; AgentIndex < Entities.Num(); ++AgentIndex)
{
FMassEntityView EntityView(EntityTemplate.GetArchetype(), Entities[AgentIndex]);
FMassAgentSubsystemHelper::InitializeAgentComponentFragments(*AgentComponents[AgentIndex], EntityView, EMassTranslationDirection::ActorToMass, ObjectFragmentInitializers);
}
}
for (int AgentIndex = 0; AgentIndex < Entities.Num(); ++AgentIndex)
{
AgentComponents[AgentIndex]->SetEntityHandle(Entities[AgentIndex]);
}
}
}
PendingAgentEntities.Reset();
for (TTuple<FMassEntityTemplateID, FMassAgentInitializationQueue>& Data : PendingPuppets)
{
const FMassEntityTemplateID EntityTemplateID = Data.Get<0>();
const TSharedRef<FMassEntityTemplate>* EntityTemplatePtr = SpawnerSystem->GetTemplateRegistryInstance().FindTemplateFromTemplateID(EntityTemplateID);
if (!ensure(EntityTemplatePtr))
{
// note that this condition is temporary, we'll be switched to a `check` once we set up characters
continue;
}
const FMassEntityTemplate& EntityTemplate = EntityTemplatePtr->Get();
const FMassArchetypeCompositionDescriptor TemplateDescriptor = EntityTemplate.GetCompositionDescriptor();
TArray<TObjectPtr<UMassAgentComponent>>& AgentComponents = Data.Get<1>().AgentComponents;
for (UMassAgentComponent* AgentComp : AgentComponents)
{
const FMassEntityHandle PuppetEntity = AgentComp->GetEntityHandle();
if (!ensureMsgf(PuppetEntity.IsSet(), TEXT("Trying to initialize puppet's fragments while the pupped doesn't have a corresponding Entity identifier set. This should not happen.")))
{
continue;
}
FMassArchetypeCompositionDescriptor& PuppetDescriptor = AgentComp->GetMutablePuppetSpecificAddition();
PuppetDescriptor = TemplateDescriptor;
EntityManager->AddCompositionToEntity_GetDelta(PuppetEntity, PuppetDescriptor);
if (EntityTemplate.GetObjectFragmentInitializers().Num())
{
const FMassArchetypeHandle ArchetypeHandle = EntityManager->GetArchetypeForEntity(PuppetEntity);
FMassEntityView EntityView(ArchetypeHandle, PuppetEntity);
FMassAgentSubsystemHelper::InitializeAgentComponentFragments(*AgentComp, EntityView, EMassTranslationDirection::MassToActor, EntityTemplate.GetObjectFragmentInitializers());
}
AgentComp->PuppetInitializationDone();
}
}
PendingPuppets.Reset();
}