UObject复制
一、覆写函数IsSupportedForNetworking 让UObject支持复制
virtual bool IsSupportedForNetworking() const override { return true; }
还需要在Actor中重写ReplicateSubobjects让子对象实现复制
// 子对象
UCLASS()
class UMagicInventory : public UObject
{
GENERATED_BODY()
public:
virtual bool IsSupportedForNetworking() const override { return true; }
UPROPERTY(Replicated)
TArray<FString> Items;
};
// Actor
UCLASS()
class AMagicBox : public AActor
{
GENERATED_BODY()
public:
AMagicBox()
{
bReplicates = true; // Actor 开启网络复制
Inventory = CreateDefaultSubobject<UMagicInventory>(TEXT("Inventory"));
}
UPROPERTY()
UMagicInventory* Inventory;
virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override
{
bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags);
if (Inventory)
{
// 将子对象 Inventory 同步到客户端
WroteSomething |= Channel->ReplicateSubobject(Inventory, *Bunch, *RepFlags);
}
return WroteSomething;
}
};
ReplicateSubobjects实现了将AMagicBox的Inventory变量同步到了客户端
如果 不重写 ReplicateSubobjects:
Inventory指针在客户端是nullptrUMagicInventory完全不存在- 后面就算
Items标了Replicated,也毫无意义
同时也要重写IsSupportedForNetworking,如果不返回true,则同样:
Inventory指针在客户端是nullptrUMagicInventory完全不存在
还需要注意的是Items的复制是GetLifetimeReplicatedProps处理的 不是ReplicateSubobjects处理的,因此UObject内的变量复制也要写完GetLifetimeReplicatedProps的一整套内容
二、注册子对象列表
是5.7版本的新功能,与ReplicateSubobjects做的事基本相同,但是更简洁,适配Iris复制系统
- 在 Actor 或 Actor Component 的构造函数中启用:
bReplicateUsingRegisteredSubObjectList = true; - 当你创建或想要复制子对象时,在运行时调用:
AddReplicatedSubObject(YourSubObject); - 当子对象销毁或不再需要复制时,调用:
RemoveReplicatedSubObject(YourSubObject);
AddReplicatedSubObject可以调用的时机?
"此刻是否已经有 ActorChannel,并且我是在服务器上?"
常用位置:
-
1.
BeginPlay()(服务器端)- 最常见
- 生命周期稳定
- 网络系统已就绪
-
2.
PostInitializeComponents()(服务器端)- 比 BeginPlay 更早
- 适合组件 / 子对象结构初始化完成后立刻注册
-
3.任何服务器逻辑函数 中
- 例如拾取、生成、绑定能力、打开箱子
- 只要满足:
- 对象已存在
- Actor 已开始复制
-
4.动态创建子对象之后立刻调用
Inventory = NewObject<UMagicInventory>(this); AddReplicatedSubObject(Inventory);
注意构造函数,OnRep_函数不能调用AddReplicatedSubObject
三、UObject中使用RPC
覆写以下函数让UObject支持RPC ,注意 UPROPERTY() int TestInt; 类中必须有一个UPROPERTY的属性,否则RPC无法调用!
#pragma region UObjectNetworking
public:
virtual bool IsSupportedForNetworking() const override
{
return true;
}
virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack)
{
int32 Callspace = FunctionCallspace::Local;
if (UObject* Outer = GetOuter()) Callspace = Outer->GetFunctionCallspace(Function, Stack);
return Callspace;
}
//要有一个UPROPERTY()修饰的变量
UPROPERTY()
int TestInt;
AActor* GetActorOuter() const
{
return GetTypedOuter<AActor>();
}
virtual bool CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) override
{
AActor* Actor = GetTypedOuter<AActor>();
if (UNetDriver* NetDriver = Actor->GetNetDriver())
{
NetDriver->ProcessRemoteFunction(Actor, Function, Parms, OutParms, Stack, this);
return true;
}
return false;
}
#pragma endregion