本帖最后由 山山山 于 2024-3-22 15:00 编辑
1. 什么是基础性能接口
不会吧不会吧,不会还有人不知道口袋方舟在0.29的版本就推出了基础性能接口,可以通过这个接口查看游戏相关性能了吧
/**
* @description 游戏性能数据,辅助 Debug 和性能优化
* @groups UTILITY
* @networkStatus usage:双端
*/
class DebugUtil {
/**
* @description 帧时间是生成一帧游戏内容所花费的总时间。由于游戏线程和渲染线程在完成一帧之前保持同步,帧时往往接近其中一个线程中显示的时间。单位ms
*/
static get frameTime(): number;
/**
* @description 对象在游戏线程中消耗的时间,包括脚本,动画,游戏逻辑等。单位ms。如果帧时接近游戏线程中显示的时间,则游戏的性能很可能会受到游戏线程的阻碍。单位ms。
*/
static get gameThreadTime(): number;
/**
* @description 在渲染线程中处理这些对象的时间,受粒子,特效,网格等影响。单位ms。
* @precautions 如果帧时接近Draw线程中显示的时间,则游戏的性能很可能会受到渲染线程的阻碍。单位ms。服务端该值为0。
*/
static get renderThreadTime(): number;
/**
* @description 当前使用的总内存大小,单位MB。
*/
static get usedMemory(): number;
/**
* @description 一秒内发出的网络包的总大小。单位 Byte
*/
static get sentBytes(): number;
/**
* @description 一秒内收到的网络包的总大小。单位 Byte。
*/
static get receivedBytes(): number;
static tsEventRpcFuncs: string[];
/**
* @description 当前帧收到的RPC消息。
*/
static get receivedRPCs(): string[];
/**
* @description 当前帧发送的RPC消息。
*/
static get sentRPCs(): string[];
/**
* @description 当前帧缓存的RPC消息。
*/
static get cachedRPCs(): string[];
}
2. 单脚本统计rpc数量
有了这个性能接口,就可以统计游戏中的rpc数量了,要知道rpc如果使用不当,有可能会导致rpc栈溢出,玩家断线的情况。
下面是一个统计游戏中rpc数量的单脚本,可以统计固定时间内的rpc数量,并以MarkDown的格式打印出来,可以更直观的看到哪些rpc过多,从而进行优化。
@Component
export default class RpcStatistic extends Script{
sentRpcs: Map<number, { [key: string]: number } > = new Map();
receivedRpcs: Map<number, {[key:string]: number}> = new Map();
@Property({displayName: "检测时间段(s)"})
checkTime: number = 30;
timer: number = 0;
curTimeRegion: number = 0;
protected onStart(): void {
this.useUpdate = true;
if(SystemUtil.isClient()){
InputUtil.onKeyDown(Keys.O,()=>{
this.printRpcs();
})
}
}
protected onUpdate(dt: number): void {
this.checkRpcs();
this.timer += dt;
if(this.timer >= this.checkTime){
this.timer = 0;
this.curTimeRegion+=this.checkTime;
}
}
checkRpcs(){
if(!this.sentRpcs.has(this.curTimeRegion)){
this.sentRpcs.set(this.curTimeRegion, {});
}
if(!this.receivedRpcs.has(this.curTimeRegion)){
this.receivedRpcs.set(this.curTimeRegion, {});
}
const curSends = this.sentRpcs.get(this.curTimeRegion);
const curReceives = this.receivedRpcs.get(this.curTimeRegion);
const sends = DebugUtil.sentRPCs;
const received = DebugUtil.receivedRPCs;
DebugUtil.cachedRPCs;
for (let i = 0; i < sends.length; i++) {
const rpc = sends[i];
if(rpc.startsWith("Type:RPC")){return};
curSends[rpc] = (curSends[rpc]?curSends[rpc]:0) + 1;
}
for (let i = 0; i < received.length; i++) {
const rpc = received[i];
if(rpc.startsWith("Type:RPC")){return};
curReceives[rpc] = (curReceives[rpc]?curReceives[rpc]:0) + 1;
}
}
@RemoteFunction(Client, Server)
printRpcs() {
let output = "# RPC数量图\n\n";
this.sentRpcs.forEach((sentRpcs, timeRegion) => {
output += `## 时间段:${timeRegion}s - ${timeRegion + this.checkTime}s\n\n`;
const sentRpcsSorted = Object.entries(sentRpcs).sort((a, b) => b[1] - a[1]);
output += "| 方法 | 发送的RPC数量 |\n";
output += "| --- | --- |\n";
sentRpcsSorted.forEach(([method, count]) => {
output += `| ${method} | ${count}次 |\n`;
});
const receivedRpcs = this.receivedRpcs.get(timeRegion);
if (receivedRpcs) {
const receivedRpcsSorted = Object.entries(receivedRpcs).sort((a, b) => b[1] - a[1]);
output += "\n| 方法 | 接收的RPC数量 |\n";
output += "| --- | --- |\n";
receivedRpcsSorted.forEach(([method, count]) => {
output += `| ${method} | ${count}次 |\n`;
});
}
output += "\n";
});
console.log(output);
}
}
3. 使用方法
a. 将这个脚本放到代码中,并在编辑器中拖到场景上;
b. 设置脚本检测时间段的大小,默认为30s;
c. 运行游戏,并对关注的内容进行游玩测试,待感觉测试的差不多的时候,点击O键,输出日志。该脚本记录了服务端和客户端的rpc,因此会在服务端及客户端都会输出。
d. 复制日志信息,保存为.md格式的文件,并在VScode中以markDown格式进行预览。
|