Skip to content

Commit 734d5db

Browse files
committed
ChildActorComponent
1 parent 637cfe0 commit 734d5db

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
2+
---
3+
title: "UE5 | ChildActorComponent Transient Child在PIE下消失的问题"
4+
date: 2024-08-15T22:49:58+08:00
5+
draft: false
6+
categories: [ "UE"]
7+
isCJKLanguage: true
8+
slug: "e488f1cb"
9+
toc: true
10+
mermaid: false
11+
fancybox: false
12+
blueprint: false
13+
# latex support
14+
# katex: true
15+
# markup: mmark
16+
# mmarktoc: false
17+
UEVersion: 5.3.2
18+
---
19+
20+
21+
# To be Transient or Not To be?
22+
23+
24+
```cpp
25+
/**
26+
* Should the spawned actor be marked as transient?
27+
* @note The spawned actor will also be marked transient if this component or its owner actor are transient, regardless of the state of this flag.
28+
*/
29+
UPROPERTY(EditDefaultsOnly, Category=ChildActorComponent)
30+
uint8 bChildActorIsTransient:1;
31+
```
32+
33+
这个Flag主要作用是给Spawn出来的ChildActor加上Transient标记。
34+
35+
带上Transient标记,所有序列化和SavePackage之类的函数都会跳过这个ChildActor。
36+
适合ChildActor可能会进行一些会导致PackageDirty的情况。
37+
38+
39+
# Bug: PIE下ChildActor消失?
40+
41+
如果带上Transient,摆在场景上的ChildActorComponent在PIE下没法看见创建的ChildActor.
42+
43+
44+
![edit-5809e22784b84ca4a70b2282f98296b6-2024-08-15-15-44-40](https://img.blurredcode.com/img/edit-5809e22784b84ca4a70b2282f98296b6-2024-08-15-15-44-40.png?x-oss-process=style/compress)
45+
46+
47+
|Editor|PIE|
48+
|-|-|
49+
|![edit-5809e22784b84ca4a70b2282f98296b6-2024-08-15-15-45-58](https://img.blurredcode.com/img/edit-5809e22784b84ca4a70b2282f98296b6-2024-08-15-15-45-58.png?x-oss-process=style/compress)|![UE_ChildActorComponent_Transient_Bug_In_PIE-2024-08-15-22-57-15](https://img.blurredcode.com/img/UE_ChildActorComponent_Transient_Bug_In_PIE-2024-08-15-22-57-15.png?x-oss-process=style/compress)
50+
|
51+
52+
53+
54+
仔细分析了一波原因,最后定位到在`ULevel::Serialize`里:
55+
56+
对于带有`Transient`标记的Actor不会被序列化到`Actors`数组里。
57+
58+
```cpp
59+
else if (Ar.IsSaving() && Ar.IsPersistent())
60+
{
61+
UPackage* LevelPackage = GetOutermost();
62+
TArray<AActor*> EmbeddedActors;
63+
EmbeddedActors.Reserve(Actors.Num());
64+
65+
Algo::CopyIf(Actors, EmbeddedActors, [&](AActor* Actor)
66+
{
67+
if (!Actor)
68+
{
69+
return false;
70+
}
71+
72+
check(Actor->GetLevel() == this);
73+
74+
if (Actor->HasAnyFlags(RF_Transient))
75+
{
76+
return false;
77+
}
78+
79+
```
80+
81+
82+
当从Editor进入到PIE时候,会进行`UWorld`的复制,`ULevel`的重新初始化,最后进入到
83+
84+
```cpp
85+
bool ULevel::IncrementalRegisterComponents(bool bPreRegisterComponents, int32 NumComponentsToUpdate, FRegisterComponentContext* Context)
86+
{
87+
// Find next valid actor to process components registration
88+
89+
if (OwningWorld)
90+
{
91+
OwningWorld->SetAllowDeferredPhysicsStateCreation(true);
92+
}
93+
94+
while (CurrentActorIndexForIncrementalUpdate < Actors.Num())
95+
{
96+
....
97+
Actor->IncrementalRegisterComponents(NumComponentsToUpdate, Context);
98+
}
99+
```
100+
101+
102+
由于`Editor`的`ChildActor`没有被序列化到`ULevels Actor`里,新建的PIE UWorld的Level将不会有这个ChildActor,所以这里会跳过Child Actor的Register。
103+
104+
所以,`ChildActor`虽然存在在PIE World(由UWorld的复制的时候带过来的,所以能正常执行BeginPlay / TickFunction),但是由于没有注册所以没有创建`RenderState`和`PhysicsState`,所以在渲染时看不到,物理上也无法交互。
105+
106+
一个简单的修复就是在 `ChildActorComponent`的`OnRegister`中,如果发现`ChildActor`没注册,重新注册。
107+
108+
109+
110+
```
111+
diff --git a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp
112+
--- a/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp
113+
+++ b/Engine/Source/Runtime/Engine/Private/Components/ChildActorComponent.cpp
114+
115+
@@ -102,6 +102,13 @@
116+
void UChildActorComponent::OnRegister()
117+
{
118+
Super::OnRegister();
119+
120+
....
121+
{
122+
CreateChildActor();
123+
}
124+
+ // register all components if necessary
125+
+ if(ChildActor && !ChildActor->HasActorRegisteredAllComponents())
126+
+ {
127+
+ ChildActor->RegisterAllComponents();
128+
+ }
129+
}
130+
131+
void UChildActorComponent::Serialize(FArchive& Ar)
132+
133+
```

0 commit comments

Comments
 (0)