[开发者心得] 用什么方法验证玩家是否在线?如何做心跳检测

[复制链接]
742 |0
啊啵呲嘚 发表于 2023-12-19 15:52:55 | 显示全部楼层 |阅读模式
本帖最后由 啊啵呲嘚 于 2023-12-19 15:52 编辑

用编辑器自带的API:

Player.onPlayerDisconnect,当玩家掉线时执行绑定函数。该委托双端触发机制不同。在客户端只被本地玩家掉线事件触发,触发时机为掉线的瞬间。在服务端被任意玩家掉线事件触发,触发时机为5秒内未收到客户端玩家消息即为掉线。
当客户端切后台、看广告等OnPause操作时,该回调在服务器上也会被触发。
Player.onPlayerDisconnect.add((player: Player) => {
    console.log('断开连接 [ userId ] >', player.userId)
  })


如何自定义心跳检测:
心跳检测的原理是,客户端每隔一段时间向服务端发送消息,服务端在一个时间间隔里没有收到该客户端的消息时,视为该客户端已经断开连接。
@Component
export default class HeartRateCheck extends Script {

  @Property({ displayName: "是否使用自定义检测时间" })
  isCustom: boolean = false;

  @Property({ displayName: "检测时间(ms)" })
  checkTime: number = 1000;


  @Property({ displayName: "断开时间(ms)" })
  delayTime: number = 1500;

  private _heartRate: Map<string, number> = new Map()
  private _intervalId: number;
  private _playerDisconnect: (player: Player) => void = (player: Player) => {
    console.log('退出 [ userId ] >', player.userId)
    HeartRateCheck.onHeartRateCheck.broadcast(player)
  }
  static readonly onHeartRateCheck: mw.MulticastDelegate<(player: Player) => void> = new mw.MulticastDelegate()

  /** 当脚本被实例后,会在第一帧更新前调用此函数 */
  protected onStart(): void {
    if (this.isCustom) {
      if (SystemUtil.isClient()) {
        this._intervalId = setInterval(() => {
          this.heartRateCheck(Player.localPlayer.userId)
        }, this.checkTime)
      }
    } else if (SystemUtil.isServer()) {
      Player.onPlayerDisconnect.add(this._playerDisconnect)
    }
  }

  @RemoteFunction(Server)
  heartRateCheck(userId: string) {
    console.log('[ userId ] >', userId)
    if (this._heartRate.has(userId)) {
      const id = this._heartRate.get(userId)
      clearTimeout(id)
    }
    this._heartRate.set(userId, setTimeout(() => {
      console.log('退出 [ userId ] >', userId)
      HeartRateCheck.onHeartRateCheck.broadcast(Player.getPlayer(userId))
    }, this.delayTime))
  }

  /**
   * 周期函数 每帧执行
   * 此函数执行需要将this.useUpdate赋值为true
   * @param dt 当前帧与上一帧的延迟 / 秒
   */
  protected onUpdate(dt: number): void {

  }

  /** 脚本被销毁时最后一帧执行完调用此函数 */
  protected onDestroy(): void {
    if (SystemUtil.isServer()) {
      if (this.isCustom) {
        for (const [, id] of this._heartRate) {
          clearTimeout(id)
        }
        this._heartRate.clear()
      } else {
        Player.onPlayerDisconnect.remove(this._playerDisconnect)
      }
    }
    if (SystemUtil.isClient() && this.isCustom) {
      if (this._intervalId) {
        clearInterval(this._intervalId)
      }
    }
  }
}

心跳检测预制体
HeartRateCheck.zip (6.35 KB, 下载次数: 45)
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表