您的位置:首页 > Web前端 > JavaScript

ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(系统保障篇)

2021-05-12 10:11 791 查看

快速上手多人游戏服务器开发。后续会基于

Google Agones
,更新相关
K8S
运维、大规模快速扩展专用游戏服务器的文章。拥抱☁️原生🤗 Cloud-Native!

系列

监控面板 (
@colyseus/monitor
)

@colyseus/monitor
是一个方便的工具,允许您查看和检查服务器生成的当前房间列表。

特性

  • 列出所有活动房间 强制安排一个特定的房间
  • 检查一个特定的房间
      查看房间的状态
    • 为客户端发送/广播消息
    • 强制断开客户端连接

    安装

    安装模块:

    npm install --save @colyseus/monitor

    将它包含在你的项目中:

    // ...
    import { monitor } from "@colyseus/monitor";
    
    // ...
    app.use("/colyseus", monitor());

    使用密码限制访问面板

    您可以使用

    express
    中间件在
    monitor
    路由上启用身份验证,例如
    express-basic-middleware

    npm install --save express-basic-auth

    使用

    express-basic-auth
    创建用户和密码。

    import basicAuth from "express-basic-auth";
    
    const basicAuthMiddleware = basicAuth({
    // list of users and passwords
    users: {
    "admin": "admin",
    },
    // sends WWW-Authenticate header, which will prompt the user to fill
    // credentials in
    challenge: true
    });
    
    app.use("/colyseus", basicAuthMiddleware, monitor());

    设置自定义房间列表列

    app.use("/colyseus", basicAuthMiddleware, monitor({
    columns: [
    'roomId',
    'name',
    'clients',
    { metadata: "spectators" }, // display 'spectators' from metadata
    'locked',
    'elapsedTime'
    ]
    }));

    如果未指定,则默认的房间列表列为:

    ['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime']

    负载测试 / 压力测试 (
    @colyseus/loadtest
    )

    当您想对服务器进行实战测试并了解它在实时环境中的性能时,

    @colyseus/loadtest
    工具非常有用。

    安装

    安装

    @colyseus/loadtest
    模块:

    npm install --save-dev @colyseus/loadtest

    用法

    colyseus-loadtest
    命令需要一些参数才能工作:

    • script
      : 该工具将要使用的自定义脚本
    • --endpoint
      : 你服务器端点 (默认使用
      ws://localhost:2567
      )
    • --room
      : 您要连接的房间名称
    • --numClients
      : 您想连接到
      room
      的客户端数量。

    示例

    这是一个脚本文件示例。基于每个连接客户端的房间生命周期事件,您可以实现一个

    "bot"
    来与
    room
    交互。

    // script.ts
    import { Room, Client } from "colyseus.js";
    
    export function requestJoinOptions (this: Client, i: number) {
    return { requestNumber: i };
    }
    
    export function onJoin(this: Room) {
    console.log(this.sessionId, "joined.");
    
    this.onMessage("*", (type, message) => {
    console.log("onMessage:", type, message);
    });
    }
    
    export function onLeave(this: Room) {
    console.log(this.sessionId, "left.");
    }
    
    export function onError(this: Room, err) {
    console.error(this.sessionId, "!! ERROR !!", err.message);
    }
    
    export function onStateChange(this: Room, state) {
    }

    把 50 个客户端连接到一个
    "battle"
    房间

    npx colyseus-loadtest script.ts --room battle --numClients 50 --endpoint ws://localhost:2567

    认证 + 社交 (
    @colyseus/social
    )

    本节介绍

    @colyseus/social
    的配置和用法。

    @colyseus/social
    是一个实验性模块,提供通用后端服务,以加快您的多人游戏开发体验。该
    API
    公开征求建议和改进。

    如果要实现自己的身份验证方法,请参见 Room » onAuth()

    安装

    1. 下载和安装 MongoDB

    2. 安装

      @colyseus/social
      模块。

    npm install @colyseus/social
    npm install express-jwt
    1. Import
      expose
      @colyseus/social
      提供的
      Express
      路由。
    import express from "express";
    import socialRoutes from "@colyseus/social/express"
    
    const app = express();
    app.use("/", socialRoutes);
    
    app.listen(8080);
    const express = require("express");
    const socialRoutes = require("@colyseus/social/express").default;
    
    const app = express();
    app.use("/", socialRoutes);
    
    app.listen(8080);

    服务器端配置

    环境变量

    • MONGO_URI
      : MongoDB 连接 URI
    • JWT_SECRET
      : 用于身份验证的安全 secret 字符串。
    • FACEBOOK_APP_TOKEN
      : Facebook App Token (
      "appid|appsecret"
      )

    服务器端 API

    @colyseus/social
    模块提供了
    MongoDB
    models 和
    token
    验证功能供您使用。

    import { User, FriendRequest, verifyToken } from "@colyseus/social";

    实现
    onAuth
    去检索当前用户

    import { User, verifyToken } from "@colyseus/social";
    
    class MyRoom extends Room {
    
    async onAuth(client, options) {
    // verify token authenticity
    const token = verifyToken(options.token);
    
    // query the user by its id
    return await User.findById(token._id);
    }
    
    onJoin(client, options, user) {
    console.log(user.username, "has joined the room!");
    }
    
    }

    Hooks

    hooks.beforeAuthenticate

    beforeAuthenticate
    钩子在用户登录或注册之前被触发。

    import { hooks } from "@colyseus/social";
    
    hooks.beforeAuthenticate((provider, $setOnInsert, $set) => {
    // assign default metadata upon registration
    $setOnInsert.metadata = {
    coins: 100,
    trophies: 0
    };
    });

    hooks.beforeUserUpdate

    beforeUserUpdate
    钩子在用户通过 save() 方法更新自己的信息之前被触发。

    import Filter from "bad-words";
    const filter = new Filter();
    
    hooks.beforeUserUpdate((_id, fields) => {
    if (fields['username'] && filter.isProfane(fields['username'])) {
    throw new Error("no_swearing_allowed");
    }
    })

    客户端 API

    登录

    匿名

    await client.auth.login();

    Email + 密码

    await client.auth.login({
    email: "user@example.com",
    password: "12345"
    });

    Facebook

    //
    // Make sure you have the Facebook SDK installed and configured first
    // - https://developers.facebook.com/docs/javascript/quickstart
    // - https://developers.facebook.com/docs/facebook-login/web
    //
    
    FB.login(function(response) {
    if (response.authResponse) {
    client.auth.login({ accessToken: response.authResponse.accessToken });
    }
    }, { scope: 'public_profile,email,user_friends' });

    更新用户数据

    您可以从客户端修改

    username
    displayName
    avatarUrl
    lang
    location
    timezone
    ,然后调用
    save()
    方法。

    client.auth.username = "Hello world!"
    await client.auth.save();

    注销

    client.auth.logout();

    获取朋友列表

    const friends = await client.auth.getFriends();
    friends.forEach(friend => {
    console.log(friend.username);
    });

    获取在线朋友列表

    const friends = await client.auth.getOnlineFriends();
    friends.forEach(friend => {
    console.log(friend.username);
    });

    获取朋友请求的列表

    const friends = await client.auth.getFriendRequests();
    friends.forEach(friend => {
    console.log(friend.username);
    });

    接受朋友的请求

    await client.auth.acceptFriendRequest(friendId);

    拒绝朋友请求

    await client.auth.declineFriendRequest(friendId);

    发送朋友请求

    await client.auth.sendFriendRequest(friendId);

    阻止用户

    await client.auth.blockUser(friendId);

    取消阻止用户

    await client.auth.unblockUser(friendId);

    调试

    Inspector

    可以使用

    Node.js
    中的内置
    inspector
    来调试应用程序。

    阅读更多关于 调试 Node.js 应用程序.

    在生产环境中使用 inspector

    在生产中使用 inspector 时要小心。使用内存快照和断点将直接影响用户的体验。

    1. 连接到远程服务器:

    ssh root@remote.example.com

    2. 检查 Node 进程的 PID

    ps aux | grep node

    3. 将 inspector 附加到进程上

    kill -usr1 PID

    4. 创建一个从本地机器到远程 inspector 的 SSH tunnel

    ssh -L 9229:localhost:9229 root@remote.example.com

    您的生产服务器现在应该出现在

    chrome://inspect
    上。

    Debug 消息

    服务器提供了一些调试消息,您可以通过设置

    DEBUG
    环境变量来逐个启用这些消息。

    要启用所有日志,可以使用以下命令运行服务器:

    DEBUG=colyseus:* node server.js

    请参阅下面所有可用的调试类别和示例输出。

    colyseus:patch

    记录向所有客户端广播补丁的字节数和时间间隔。

    colyseus:patch "chat" (roomId: "ryWiL5rLTZ") is sending 28 bytes: +57ms

    colyseus:errors

    在服务器端发生意外(或内部预期)错误时记录日志。

    colyseus:matchmaking

    每当房间

    spanwed
    disposed
    时都要记录。

    colyseus:matchmaking spawning 'chat' on worker 77218 +52s
    colyseus:matchmaking disposing 'chat' on worker 77218 +2s

    部署

    Heroku

    Heroku
    仅用于原型设计。你可以通过点击这个按钮来部署 colyseus-examples 项目:

    Nginx (推荐)

    建议在生产环境中使用

    pm2
    nginx

    PM2

    在您的环境中安装

    pm2

    npm install -g pm2

    然后使用它启动你的服务器:

    pm2 start your-server.js

    Nginx 配置

    server {
    listen 80;
    server_name yourdomain.com;
    
    location / {
    proxy_pass http://localhost:2567;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
    }
    }

    使用 SSL 配置 Nginx

    建议从 LetsEncrypt 获取证书。

    server {
    listen 80;
    listen 443 ssl;
    server_name yourdomain.com;
    
    ssl_certificate /path/to/your/cert.crt;
    ssl_certificate_key /path/to/your/cert.key;
    
    location / {
    proxy_pass http://localhost:2567;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_read_timeout 86400s;
    proxy_send_timeout 86400s;
    }
    }

    Apache

    下面介绍如何使用

    Apache
    作为
    Node.js Colyseus
    应用程序的代理(Thanks tomkleine!)

    安装所需的

    Apache
    模块:

    sudo a2enmod ssl
    sudo a2enmod proxy
    sudo a2enmod proxy_http
    sudo a2enmod proxy_html
    sudo a2enmod proxy_wstunnel

    虚拟主机配置:

    <VirtualHost *:80>
    ServerName servername.xyz
    
    # Redirect all requests received from port 80 to the HTTPS variant (force ssl)
    RewriteEngine On
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
    
    </VirtualHost>
    
    <VirtualHost *:443>
    ServerName servername.xyz
    
    # enable SSL
    SSLEngine On
    SSLCertificateFile          /PATH/TO/CERT/FILE
    SSLCertificateKeyFile       /PATH/TO/PRIVATE/KEY/FILE
    
    #
    # setup the proxy to forward websocket requests properly to a normal websocket
    # and vice versa, so there's no need to change the colyseus library or the
    # server for that matter)
    #
    # (note: this proxy automatically converts the secure websocket (wss)
    
    RewriteEngine On
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$           [NC,OR]
    RewriteCond %{HTTP:CONNECTION} ^Upgrade$          [NC]
    RewriteRule .* ws://127.0.0.1:APP-PORT-HERE%{REQUEST_URI}  [P,QSA,L]
    
    # setup the proxy to forward all https requests to http backend
    # (also automatic conversion from https to http and vice versa)
    
    ProxyPass "/" "http://localhost:APP-PORT-HERE/"
    ProxyPassReverse "/" "http://localhost:APP-PORT-HERE/"
    
    </VirtualHost>

    greenlock-express

    如果您希望在服务器上快速配置

    SSL
    ,而不需要配置反向代理(
    reverse-proxy
    ),
    Greenlock
    是一个很好的工具。

    当使用

    greenlock-express
    时,你不应该在它背后配置任何反向代理,比如 NginxApache

    npm install --save greenlock-express

    请先遵循 greenlock-express 的 README 部分

    下面是处理开发环境(

    development
    )和生产环境(
    production
    )的推荐方法:

    import http from "http";
    import express from "express";
    import { Server } from "colyseus";
    
    function setup(app: express.Application, server: http.Server) {
    const gameServer = new Server({ server });
    
    // TODO: configure `app` and `gameServer` accourding to your needs.
    // gameServer.define("room", YourRoom);
    
    return app;
    }
    
    if (process.env.NODE_ENV === "production") {
    require('greenlock-express')
    .init(function () {
    return {
    greenlock: require('./greenlock'),
    cluster: false
    };
    })
    .ready(function (glx) {
    const app = express();
    
    // Serves on 80 and 443
    // Get's SSL certificates magically!
    glx.serveApp(setup(app, glx.httpsServer(undefined, app)));
    });
    
    } else {
    // development port
    const PORT = process.env.PORT || 2567;
    
    const app = express();
    const server = http.createServer(app);
    
    setup(app, server);
    server.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`));
    }

    Docker

    先决条件:

    • package.json
      package-lock.json
      在项目中。

    • 设置

      npm start
      命令,使其启动服务器。

    步骤:

    Step 1 安装 Docker

    Step 2 在 colyseus 项目的根目录中创建

    Dockerfile

    FROM node:12
    
    ENV PORT 8080
    
    WORKDIR /usr/src/app
    
    # A wildcard is used to ensure both package.json AND package-lock.json are copied
    COPY package*.json ./
    
    RUN npm ci
    # run this for production
    # npm ci --only=production
    
    COPY . .
    
    EXPOSE 8080
    
    CMD [ "npm", "start" ]

    Step 3 在同一目录中创建

    .dockerginore
    文件

    node_modules
    npm-debug.log

    这将防止您的本地模块和调试日志被复制到您的 Docker 镜像中,并可能覆盖安装在镜像中的模块。

    Step 4 进入

    Dockerfile
    所在的目录,运行以下命令构建
    Docker
    镜像。
    -t
    flag 可以让你标记你的
    image
    ,这样以后使用
    docker images
    命令更容易找到:

    docker build -t <your username>/colyseus-server .

    Step 5 你的

    image
    现在将由
    Docker
    用以下命令列出:

    docker images

    输出:

    # Example
    REPOSITORY                      TAG        ID              CREATED
    node                            12         1934b0b038d1    About a minute ago
    <your username>/colseus-server    latest     d64d3505b0d2    About a minute ago

    Step 6 使用以下命令运行 Docker 镜像:

    docker run -p 8080:8080 -d <your username>/colyseus-server

    使用

    -d
    运行镜像将以
    detached
    模式运行容器,使容器在后台运行。
    -p flag
    将公共端口重定向到容器内的私有端口。

    Step 7 完成后,现在可以使用

    localhost:8080
    连接到服务器

    更多信息:

    高可用,可扩展

    这个文档是一个正在进行的工作。

    要将

    Colyseus
    扩展到多个进程或服务器,你需要有
    Redis
    MongoDB
    和一个动态代理(
    dynamic proxy
    )。

    Redis

    下载并安装 Redis。使用

    RedisPresence

    import { Server, RedisPresence } from "colyseus";
    
    const gameServer = new Server({
    // ...
    presence: new RedisPresence(),
    });
    const colyseus = require("colyseus");
    
    const gameServer = new colyseus.Server({
    // ...
    presence: new colyseus.RedisPresence(),
    });

    presence
    用于从一个进程到另一个进程调用房间
    "seat reservation"
    功能,并允许开发人员跨
    rooms
    利用一些数据共享功能。请参阅 Presence API

    每个

    Colyseus
    进程还将自己的
    processId
    和网络位置注册到
    presence
    API,稍后 dynamic proxy 服务将使用该
    API
    。在
    graceful shutdown
    期间,进程注销自己。

    MongoDB

    下载并安装 MongoDB。安装

    mongoose
    软件包:

    npm install --save mongoose

    使用

    MongooseDriver
    :

    import { Server, RedisPresence } from "colyseus";
    import { MongooseDriver } from "colyseus/lib/matchmaker/drivers/MongooseDriver"
    
    const gameServer = new Server({
    // ...
    driver: new MongooseDriver(),
    });
    const colyseus = require("colyseus");
    const MongooseDriver = require("colyseus/lib/matchmaker/drivers/MongooseDriver").MongooseDriver;
    
    const gameServer = new colyseus.Server({
    // ...
    driver: new MongooseDriver(),
    });

    您可以将

    MongoDB
    连接
    URI
    传递给
    new MongooseDriver(uri)
    构造函数,或者设置
    MONGO_URI
    环境变量。

    driver
    用于存储和查询可用于
    matchmaking
    rooms

    运行多个 Colyseus 进程

    要在同一台服务器上运行多个

    Colyseus
    实例,需要每个实例监听不同的端口号。建议使用
    3001
    3002
    3003
    等端口。Colyseus 进程不应公开。只有
    dynamic proxy
    是。

    强烈推荐使用PM2进程管理器来管理多个

    Node.js
    应用程序实例。

    PM2 提供了一个

    NODE_APP_INSTANCE
    环境变量,其中包含每个进程的不同编号。使用它来定义端口号。

    import { Server } from "colyseus";
    
    // binds each instance of the server on a different port.
    const PORT = Number(process.env.PORT) + Number(process.env.NODE_APP_INSTANCE);
    
    const gameServer = new Server({ /* ... */ })
    
    gameServer.listen(PORT);
    console.log("Listening on", PORT);
    npm install -g pm2

    使用以下

    ecosystem.config.js
    配置:

    // ecosystem.config.js
    const os = require('os');
    module.exports = {
    apps: [{
    port        : 3000,
    name        : "colyseus",
    script      : "lib/index.js", // your entrypoint file
    watch       : true,           // optional
    instances   : os.cpus().length,
    exec_mode   : 'fork',         // IMPORTANT: do not use cluster mode.
    env: {
    DEBUG: "colyseus:errors",
    NODE_ENV: "production",
    }
    }]
    }

    现在你已经准备好开始多个

    Colyseus
    进程了。

    pm2 start

    "PM2 和 TypeScript":建议在运行

    pm2 start
    之前通过
    npx tsc
    编译
    .ts
    文件。或者,你可以为
    PM2
    安装
    TypeScript
    解释器(
    pm2 install typescript
    ),并设置
    exec_interpreter: "ts-node"
    (read more)。

    动态代理

    @colyseus/proxy 是一个动态代理,它会自动监听

    Colyseus
    进程的上下变化,允许
    WebSocket
    连接到创建了房间的正确进程和服务器上。

    代理应该绑定到端口

    80
    /
    443
    ,因为它是应用程序惟一的公共端点。所有请求都必须通过代理。

    npm install -g @colyseus/proxy

    环境变量

    配置以下环境变量以满足您的需求:

    • PORT
      是代理将运行的端口。
    • REDIS_URL
      是你在
      Colyseus
      进程中使用的同一个
      Redis
      实例的路径。

    运行代理

    colyseus-proxy
    
    > {"name":"redbird","hostname":"Endels-MacBook-Air.local","pid":33390,"level":30,"msg":"Started a Redbird reverse proxy server on port 80","time":"2019-08-20T15:26:19.605Z","v":0}

    Refs

    中文手册同步更新在:

    • https:/colyseus.hacker-linner.com
    我是为少
    微信:uuhells123
    公众号:黑客下午茶
    加我微信(互相学习交流),关注公众号(获取更多学习资料~)
  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐