[解决方案]微信小游戏在Creator3.x中使用colyseus0.15+版本的方法

记录一下我这几天升级colyseus版本的一些采坑。

我尝试将colyseus版本升级到0.15+之后,按照官方npm重新安装,

导入

import Colyseus from "colyseus.js"

结果在cocos中提示

“Current environment does not provide a require() for requiring ‘events’.”

后来我又通过直接导入

import Colyseus from "../colyseus-sdk/colyseus.js";

的方式加载编译后的js文件。

到此web版本可以正常连接socket。

但是,当我编译为微信小游戏中遇到报错,提示fetch或者XMLHttpRequest不存在,这是因为在加入房间时,客户端要发起一个colyseus内部的post请求。但我不清楚cocos的adapter编译为什么没生效。在微信小游戏端仍然在执行fetch或者XMLHttpRequest(0.15.20版本以下是XMLHttpRequest,以上为fetch),于是我对colyseus.js的send函数做了改造,在fetch请求部分添加了对wx.request的支持。

这里以colyseus0.15.20以上版本(fetch)版本为例

修改\colyseus-sdk\colyseus.js中的send方法。

function send(method, uri, opts) {
    	opts = opts || {};
    	var timer, ctrl, tmp=opts.body;

    	opts.method = method;
    	opts.headers = opts.headers || {};

    	if (tmp && typeof tmp == 'object') {
    		opts.headers['content-type'] = 'application/json';
    		opts.body = JSON.stringify(tmp);
    	}

    	if (opts.withCredentials) {
    		opts.credentials = 'include';
    	}

    	if (opts.timeout) {
    		ctrl = new AbortController;
    		opts.signal = ctrl.signal;
    		timer = setTimeout(ctrl.abort, opts.timeout);
    	}

    	return new Promise((res, rej) => {
            if(window.wx){
                window.wx.request({
                    url: uri,
                    method: opts.method || 'GET',
                    data: opts.body,
                    header: opts.headers,
                    success: (rr) => {
                        console.log("JSON.parse1",rr)
                        clearTimeout(timer);
        
                        // apply(rr, rr); //=> rr.headers
                        let reply = rr.statusCode >= 400 ? rej : res;
        
                        let tmp = rr.header['Content-Type'];
                        if (!tmp || tmp.indexOf('application/json') === -1) {
                            reply(rr);
                        } else {
                            try {
                                console.log("JSON.parse",rr.data,opts.reviver,rr,opts)
                                // rr.data = JSON.parse(rr.data, opts.reviver);
                                reply(rr);
                            } catch (err) {
                                err.headers = rr.headers;
                                // apply(rr, err);
                                rej(err);
                            }
                        }
                    },
                    fail: (err) => {
                        err.timeout = ctrl && ctrl.signal.aborted;
                        rej(err);
                    }
                });
            }else{
                fetch(uri, opts).then((rr, reply) => {
                    clearTimeout(timer);
    
                    apply(rr, rr); //=> rr.headers
                    reply = rr.status >= 400 ? rej : res;
    
                    tmp = rr.headers.get('content-type');
                    if (!tmp || !~tmp.indexOf('application/json')) {
                        reply(rr);
                    } else {
                        rr.text().then(str => {
                            try {
                                rr.data = JSON.parse(str, opts.reviver);
                                reply(rr);
                            } catch (err) {
                                err.headers = rr.headers;
                                apply(rr, err);
                                rej(err);
                            }
                        });
                    }
                }).catch(err => {
                    err.timeout = ctrl && ctrl.signal.aborted;
                    rej(err);
                });
            }

    		
    	});
    }

注意:socket似乎可以被cocos的adapter识别成功,所以socket部分不用做改造。

cocos新人,这可能不是最优解决方案,如有更好的建议欢迎回贴提出意见。

2赞

colyseus所有服务都是完全免费的吗?

colyseus有cloud版本,用户自己写脚本传上去就好,是按量付费的,但代码都是开源的,自己部署的话,就是免费的。

1赞

再补充一个问题,发布到真机环境的时候会提示URL不存在;

继续尝试修改colyseus-sdk\colyseus.js文件

解决方案,添加一个新的方法

  function splitURL(url) {
        // 匹配URL的正则表达式
    var urlPattern = /^(?:([A-Za-z]+):)?(?:\/\/)?(?:([0-9.\-A-Za-z]+)(?::(\d+))?)?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/;
    var matches = url.match(urlPattern);

    if (!matches) {
        throw new Error("Invalid URL");
    }

    return {
        protocol: matches[1]+":" || "",
        hostname: matches[2] || "",
        port: matches[3] || "",
        pathname: matches[4] || "/"
    };

    }

全局查找,然后替换下面的代码(注释部分是被替换掉的代码)

// var url = (settings.startsWith("/"))
//     ? new URL(settings, DEFAULT_ENDPOINT)
//     : new URL(settings);
var url = (settings.startsWith("/"))
? splitURL(DEFAULT_ENDPOINT+settings)
: splitURL(settings);

mark mark