You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Colyseus v0.12.0如何在onLeave回调中区分玩家杀进程与网络掉线

问题解决方案

核心实现思路

  • 通过前端主动上报+服务端状态标记的方案区分consented=false下的两种离线场景
  • 移动端监听应用即将被销毁的生命周期事件,提前向服务端发送主动退出标记
  • 服务端收到标记后存储到对应用户的状态中,onLeave触发时读取状态判断离线原因

前端实现(以移动端为例)

不管是用Cocos/Unity开发原生应用还是Webview套壳,都可以监听应用退到后台/即将被销毁的事件,触发时发送自定义事件:

// 前端示例代码,Web端直接监听页面销毁事件
window.addEventListener('beforeunload', () => {
  // 向服务端发送主动杀进程标记
  client.send('clientBeforeKill', {});
});
// 原生开发可在iOS的applicationWillTerminate回调、Android的onDestroy回调中触发该消息发送

服务端实现修改

首先在房间初始化的onCreate回调中添加自定义事件监听:

onCreate(options) {
  // 保留你原有的初始化逻辑
  // 新增主动杀进程事件监听
  this.onMessage('clientBeforeKill', (client, data) => {
    // 给该玩家标记主动杀进程状态
    if(this.state.players[client.sessionId]) {
      this.state.players[client.sessionId].isManualKill = true;
    }
  });
}

修改后的完整onLeave代码如下:

async onLeave(client, consented) {
    console.log("===============Leave ================");
    console.log(consented, "----Client Left----", client.sessionId);
    const leavingPlayer = this.state.players[client.sessionId];
    console.log(consented, "---------- Left----", leavingPlayer?.name);
    console.log(consented, "---------- player----", this.ClientUserName);

    try {
        if (consented) {
            // 原有游戏内主动退出的逻辑保持不变
            console.log("----consented true----", client.sessionId);
            console.log("--------ROOM DISOPOSED------consented", this.ourRoomName);

            if (this.ClientUserName[0] === leavingPlayer.name) {
                this.playersInRoom = 0;
                console.log("1111111111111111111111");
                this.broadcast(
                    {
                        en: "QuitLobby",
                        value: "host quit the lobby",
                    }, { except: client });
                this.disconnect();
                this.ClientId = [];
                this.ClientAvatar = [];
                this.setState(this.state);
            }
            else {
                this.playersInRoom--;
                this.playerCount--;
                console.log(this.users.length)
                for (let i = 0; i < this.ClientUserName.length; i++) {
                    if (this.ClientUserName[i] === leavingPlayer.name) {
                        this.ClientUserName.splice(i, 1);
                        this.ClientId.splice(i, 1);
                        this.ClientAvatar.splice(i, 1);
                        this.users.splice(i + 1, 1);
                    }
                }
                console.log(this.playersInRoom)
                console.log(this.users.length)
                this.broadcast({
                    en: 'playerInfo',
                    playerData: {
                        idArr: this.ClientId,
                        nameArr: this.ClientUserName,
                        avatarArr: this.ClientAvatar
                    }
                })
            }
        }
        else {
            // 新增逻辑:判断是否是主动杀进程
            if(leavingPlayer?.isManualKill) {
                // 主动杀进程逻辑:直接广播计分板、销毁房间
                this.broadcast({
                    en: 'ShowScoreBoard',
                    value: '玩家主动退出游戏'
                });
                this.playersInRoom = 0;
                this.disconnect();
                this.ClientId = [];
                this.ClientAvatar = [];
                this.setState(this.state);
                return;
            }
            // 剩下的是网络故障场景,走原有重连逻辑
            this.broadcast({
                en: 'DisconnectedTemp',
                value: client.sessionId,
            })
            await this.allowReconnection(client, 20);
            leavingPlayer.connected = true;
            console.log("----Client Reconnect----", client.sessionId);
        }
    } catch (e) {
        // 重连超时逻辑:广播计分板、删除离线玩家
        this.broadcast({
            en: 'ShowScoreBoard',
            value: '玩家重连超时,游戏结束'
        });
        delete this.state.players[client.sessionId];
    }
}

补充说明

  • 该方案覆盖率可达99%以上,极端场景如果系统强制杀进程没来得及上报,会被判定为网络故障走重连逻辑,属于可接受的降级处理
  • 如果不想依赖前端上报,也可以调整Colyseus服务端的pingInterval(ping包发送间隔,默认3000ms)和pingMaxRetries(最大重试次数,默认2)参数,网络故障触发onLeave的时间会比主动杀进程晚,可通过时间差判断,但准确率低于主动上报方案

内容的提问来源于stack exchange,提问作者Aarju

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 12:06:03