I created my own UInstancedActorsComponent, so I can have the opportunity to modify the mass config.
I want to create a simple gameplay feature, so on interaction with an actor I “hide” this actor (and mass representation as well) and restore this actor after 5 minutes.
For that, I need to have access to the UInstancedActorsData.
Problem is FInstancedActorsInstanceHandle is never set inside UInstancedActorsComponent. This is always an invalid handle on every NetMode (Server/Client, doesn’t matter).
On the Server code trying to set this through UInstancedActorsComponent::InitializeComponent() -> UServerInstancedActorsSpawnerSubsystem::OnInstancedActorComponentInitialize()
void UServerInstancedActorsSpawnerSubsystem::OnInstancedActorComponentInitialize(UInstancedActorsComponent& InstancedActorComponent) const { if (InstancedActorComponent.GetOwner() == TransientActorBeingSpawned) { check(TransientActorSpawningInstance.IsValid()); InstancedActorComponent.InitializeComponentForInstance(TransientActorSpawningInstance); } }
But the thing is that TransientActorBeingSpawned variable is set after the actor being spawned. So if UInstancedActorsComponent is a part of this actor (added in BP or default subobject) - UInstancedActorsComponent::InitializeComponent() will be called before TransientActorBeingSpawned is set, resulting in the issue where FInstancedActorsInstanceHandle is always invalid and there is no way of getting this data from the gameplay code.
`ESpawnRequestStatus UServerInstancedActorsSpawnerSubsystem::SpawnActor(FConstStructView SpawnRequestView, TObjectPtr& OutSpawnedActor, FActorSpawnParameters& InOutSpawnParameters) const
{
…
OutSpawnedActor = World->SpawnActor(SpawnRequest.Template, SpawnRequest.Transform, InOutSpawnParameters);
if (ensureMsgf(OutSpawnedActor, TEXT(“Failed to spawn actor of class %s”), *GetNameSafe(SpawnRequest.Template.Get())))
{
TransientActorBeingSpawned = OutSpawnedActor;`
My question is:
- Am I correct that this is the issue with implementation? And if not, how can I get UInstancedActorsData/FMassEntityHandle from gameplay code on a dedicated server?
- What is the easiest way of implementing the mechanic I mentioned at the beginning of this description? Using InstancedActors, of course, because the goal is to have thousands of collectible objects in a map. They may have different visual states, etc.
Hey. Sorry for the delayed response. This thread got lost in the weeds, apparently.
Apply the following changes and let me know if it helped. I’ll work on pushing these changes to 5.6.
`==== Engine/Plugins/Runtime/InstancedActors/Source/InstancedActors/Private/InstancedActorsComponent.cpp#1 (text) ====
[Content removed]7 @@
// @todo Add support for non-replay NM_Standalone where we should call OnInstancedActorComponentInitialize
UWorld* World = GetWorld();
- if (World && World->GetNetMode() == NM_DedicatedServer)
- if (World && World->GetNetMode() != NM_Client)
{
UServerInstancedActorsSpawnerSubsystem* ServerInstancedActorSpawnerSubystem = UE::InstancedActors::Utils::GetServerInstancedActorsSpawnerSubsystem(*World);
if (IsValid(ServerInstancedActorSpawnerSubystem))
[Content removed]7 @@
void UInstancedActorsComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// Deregister Actor from entity on clients
- if (!IsNetMode(NM_DedicatedServer) && InstanceHandle.IsValid())
- if (GetNetMode() == NM_Client && InstanceHandle.IsValid())
{
AActor* Owner = GetOwner();
if (ensure(Owner))
==== Engine/Plugins/Runtime/InstancedActors/Source/InstancedActors/Private/ServerInstancedActorsSpawnerSubsystem.cpp#1 (text) ====
[Content removed]9 @@
};
InOutSpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
- // we’re going to call FinishSpawning only if the input params don’t indicate that the caller wants to do it themselves
- const bool bCallFinishSpawning = (InOutSpawnParameters.bDeferConstruction == false);
- InOutSpawnParameters.bDeferConstruction = true;
OutSpawnedActor = World->SpawnActor(SpawnRequest.Template, SpawnRequest.Transform, InOutSpawnParameters);
if (ensureMsgf(OutSpawnedActor, TEXT(“Failed to spawn actor of class %s”), *GetNameSafe(SpawnRequest.Template.Get())))
[Content removed]11 @@
InstancedActorComponent->SetIsReplicated(true);
InstancedActorComponent->RegisterComponent();
}
+
- if (bCallFinishSpawning)
- {
- OutSpawnedActor->FinishSpawning(SpawnRequest.Transform);
- }
}
return IsValid(OutSpawnedActor) ? ESpawnRequestStatus::Succeeded : ESpawnRequestStatus::Failed;`Cheers,
--mieszko
Thank you, Mieszko.
I applied those changes, and the issue was resolved. Also, thank you for fixing the problem with Standalone.
It would be great if you could provide some suggestions about the basic feature I’m trying to achieve. Like hide/show instanced actors. At the moment, I’m removing FMassStationaryISMSwitcherProcessorTag and FInstancedActorsVisualizationProcessorTag, as well as triggering deinitialization logic.
I’m relatively new to mass, so I would appreciate if you could share some best practices on how to work with mass in a multiplayer environment.
And what do I need to do to change the location of a mass entity? So ICM could “move” if needed.
Thank you in advance.
Best regards,
Alexander
Do the actors, that you want to “hide”, retain any “state” between activations? If not, consider just removing them and then recreating. Note that adding instanced actors at runtime isn’t quite supported yet. I did start work on it, so most of the stuff required for that is there, but some bits are still missing and you might need to add those yourself.
If they do retain a state, or just want to avoid creation cost (but don’t mind memory cost of keeping hidden actors around), you can force entities’ LOD off and disable LOD processing on them - `UInstancedActorsStationaryLODBatchProcessor::Execute` does something similar - things that switch between Batch- and Detailed-LOD get their tags modified to influence which processors will handle the modified entities.
Re making instanced actors change location: it’s not supported at the moment. But you can change locations of mass entities that are visualized with other visualizers. See CitySample for example how the moving vehicles and pedestrians are implemented.
Re working with Mass in multiplayer environment, one critical thing missing is Mass’s native replication. That’s why InstancedActors do their own replication.