[程式] UE4发送RPC给server失败的解决方法

楼主: yekdniw (yekdniw)   2018-01-04 20:36:23
网页版
https://yekdniwunrealengine.blogspot.tw/2018/01/pawnrpcserver.html
先前有遇到在某个class发送RPC (Remote procedure calls)都正常,
但是在某一个特定的class发送就发生server收不到的状况。
经过一番追查后发现原因在于Pawn的GetNetConnection()跟
Actor的GetNetConnection()行为是有所不同的。
一般的Actor如果没有特别override的话,就是以Actor的Owner递回去寻找,
直到找到PlayerController。
但是Pawn如果有controller posses的话,会以Controller的NetConnection()作依据。
如果这时候Controller没有设定Owner(或是其NetConnection没有连通)的话,
这时候RPC就会失败。
实验环境
以下纪录整个干净的实验环境 (UE4.18)
1. 首先创造一个Class,TestPawn。TestPawn的ClassDefault的ControllerClass
指向AIController。
2. TestPawn实作一个Client通知server的RPC,然后再实作一个server广播给
其他人的RPC。如下图所示:
[图1]
3. 到PlayerController或是PlayerPawn的Class实作Client请求Server在
Sever端生成TestPawn的程式,如下图所示:
[图2]
4. 记得执行的时候要开启dedicated server模式,或是叫两个client起来,然后
非server的玩家按F的时候,TestPawn会被spawn,会印字串
Client notify to server,但是不会看到server receive from client
后续的字串,显示RPC是失败的。
5. 此时如果追TestPawn的GetNetConnection()会发现回传的是Null,原因是
因为Controller不是Null,但是Controller的GetNetConnection()是Null。
Engine\Source\Runtime\Engine\Private\Pawn.cpp line524
6. 而Controller的NetConnection有问题的原因源自于如果APawn如果有给
ControllerClass的话,server会执行Pawn::SpawnDefaultController(),
但是不会设定这个controller的Owner。
一个没有Owner的controller其NetConnection()自然就会回传Null。
Engine\Source\Runtime\Engine\Private\Pawn.cpp line313
解决方法
要解决这个RPC收不到的方法答案就在
Engine\Source\Runtime\Engine\Private\Pawn.cpp line318
在controller一被生成的时候就会呼叫Posses,在这里面指定正确的Owner的话,
后续Pawn的RPC就能够正常运作了。
备注
其实严格来讲这个现象不叫做server收不到RPC,经过trace code的结果,
其实对client来说RPC是有送出的,server也有收到封包,也有收到Brunch,
server是在最后要转发给client的时候发现NetConnection是Null才档掉的。
也就是说这种状况其实是会产生有网络传输量的~
RPC相关程式码Trace
以下列出RPC相关的程式码位置
NetConnection line 1318
Channel->ReceivedRawBunch
走到这边代表RPC的资料有收到
DataChannel line 386
Channel->ReceivedNextBunch
Channel->ReceivedSequencedBunch
Channel->ReceiveBunch
Channel->ProcessBunch
DataReplication::ReceivedBunch line 721
bool bSuccess = ReceivedRPC
DataReplication::ReceivedRPC line 843
Object->ProcessEvent
走到此行代表RPC成功,马上就会呼叫到相关的函式
一些对RPC除错的console command
开启Log的方式 在console command下
Log [Log名称] all
关闭Log的方式 在console command下
Log [Log名称] Fatal
LogRepTraffic
可以利用LogRepTraffic追踪资料传输的状况
传送端:
一个RPC传送有三行的log
Sent RPC: [ClassName]::[FunctionName]
Sending: FOutBunch: Channel[CHID] ChSequence[SEQ]
UNetConnection::SendRawBunch. ChIndex:[CHID]. PacketID:[PID]
接收端:
一个RPC接收有三行的Log
Received: FInBunch: Channel[CHID] ChSequence[SEQ] PacketID:[PID]
Reliable Bunch, Channel[CHID] Sequence[SEQ]
Actor [ClassFullName]
LogRep
在RPC传送与接收都有成功的状况,可以从LogRep知道讯息
LogRep: Verbose: Rejected unwanted function [FunctionName] in [ClassName]
看到此讯息可能代表Actor的NetConnection是Null。
作者: coolrobin (泳圈)   2018-01-04 22:42:00
推推
作者: damody (天亮damody)   2018-01-05 02:23:00
123

Links booklink

Contact Us: admin [ a t ] ucptt.com