<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Colyseus 中的 &quot;Filter&quot;]]></title><description><![CDATA[<p><strong>Filter 是什么意思?<br />
Filter 这个词在检索和匹配类的程序中经常见到.<br />
比如下面这个网站.</strong></p>
<p><img src="/assets/uploads/files/1672746182786-00-resized.jpg" alt="0_1672746177268_00.jpg" class="img-responsive img-markdown" /></p>
<p><strong>Type to filter... 这里我们填写关键词,</strong></p>
<p><img src="/assets/uploads/files/1672746211795-01-resized.jpg" alt="0_1672746210946_01.jpg" class="img-responsive img-markdown" /></p>
<p><strong>匹配程序精准地帮我们找到了需要的内容.<br />
Colyseus 里面有两处与 Filter 有关的地方. 一个是 Matchmaking 用的 filterBy(); 一个是 Schema 用的 @filter 装饰器.</strong></p>
<hr />
<h3>RegisteredHandler.filterBy()</h3>
<p><strong>这次我们用 Colyseus Server + Cocos Creator Client 来做展示.</strong></p>
<p><strong>首先建立服务器环境.</strong></p>
<p><img src="/assets/uploads/files/1672914629293-19e93398-283a-41cb-8a16-49dd31537d5b-image-resized.png" alt="0_1672914626753_19e93398-283a-41cb-8a16-49dd31537d5b-image.png" class="img-responsive img-markdown" /></p>
<p><strong>不知道这个菜单哪里来的的话请</strong><a href="https://discuss.colyseus.io/topic/633/%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95-%E5%9C%A8%E6%AD%A4%E5%88%9B%E5%BB%BA-colyseus" rel="nofollow">参考这里</a>.</p>
<p><strong>新建 Cocos 项目, 安装 Colyseus 客户端 SDK.</strong></p>
<p><img src="/assets/uploads/files/1672746223880-1-resized.jpg" alt="0_1672746222679_1.jpg" class="img-responsive img-markdown" /></p>
<p><strong>如果发现导入时报错,</strong></p>
<p><img src="/assets/uploads/files/1672746233419-2-resized.jpg" alt="0_1672746232472_2.jpg" class="img-responsive img-markdown" /><br />
<strong>要在 tsconfig.json 文件中开启 <code>allowSyntheticDefaultImports</code> 参数.</strong></p>
<p><img src="/assets/uploads/files/1672746250841-3-resized.jpg" alt="0_1672746249762_3.jpg" class="img-responsive img-markdown" /><br />
<strong>好了, 准备工作结束, 让我们来连接房间看看.</strong></p>
<p><img src="/assets/uploads/files/1672747119488-5-resized.jpg" alt="0_1672747117496_5.jpg" class="img-responsive img-markdown" /></p>
<p><strong><code>joinOrCreate</code> 函数的第一个参数是房间名, 第二个参数是自定义的房间参数.<br />
这里我们自定义一个叫做 <code>mode</code> 的参数, 值为 <code>duo</code>, 表示是双人游戏房间.</strong></p>
<pre><code>this.room = await this.client.joinOrCreate(&quot;my_room&quot;, { mode: &quot;duo&quot; });
</code></pre>
<p><img src="/assets/uploads/files/1672746264391-4-resized.jpg" alt="0_1672746263798_4.jpg" class="img-responsive img-markdown" /></p>
<p><strong>在服务器端, 我们定义了房间名 my_room, 然后后面跟着一个 filterBy, 里面有两个过滤参数, &quot;mode&quot; 和 &quot;level&quot;.</strong></p>
<pre><code>gameServer.define('my_room', MyRoom).filterBy([&quot;mode&quot;, &quot;level&quot;]);

</code></pre>
<p><strong>它的意思是, 在进行房间匹配的时候, 把所有房间根据 &quot;mode&quot; 和 &quot;level&quot; 两个参数过滤, 只有这两个参数 <code>完全匹配</code> 的玩家才可以匹配进入相应房间.<br />
还记得客户端连接时的需求吗? 玩家要进入 &quot;mode&quot; 为 &quot;duo&quot; 的房间, &quot;level&quot; 没有指定.<br />
匹配器会根据 server 上已有的没有锁定的房间, 过滤出 &quot;mode&quot; 为 &quot;duo&quot; 的, &quot;level&quot; 为 null 的房间, 如果存在, 优先进入; 如果不存在, 新建一个这样的房间再进入.<br />
如果客户端没有要求参数, 如何匹配房间呢? 匹配器会寻找  &quot;mode&quot; 为 &quot;null&quot; 而且 &quot;level&quot; 为 &quot;null&quot; 的房间优先匹配进入; 对于 &quot;mode&quot; 为 &quot;duo&quot; 的房间, 它是 <code>不考虑在内</code> 的.<br />
除了 filterBy, 常用的还有一个 sortBy, 两个联合使用又是什么意思呢?</strong></p>
<pre><code>gameServer.define('my_room', MyRoom).filterBy([&quot;mode&quot;]).sortBy({level:-1});

</code></pre>
<p><strong>sortBy 的意思是排序. 根据参数值升序 (+) 或者降序 (-) 排序, 然后进行优先匹配.</strong><br />
<strong>上面那条语句的意思是, 寻找 mode 一致的, 按 level 从大到小排列, 选最大的, 进行匹配.</strong><br />
<strong>可以看出, filterBy 的作用就是告诉匹配器, 如何寻找, 找什么样的房间, 来给客户端进行分配.</strong></p>
<hr />
<h3>Schema 的  @filter 装饰器</h3>
<p><strong>众所周知(?), Schema 是会自动同步到房间的每一个客户端中的, 是 &quot;服务器权威&quot; 模式的基础.<br />
但是有时候, 我们需要某个客户端只能知道 Schema 的一部分而非全部.<br />
典型的需求就是牌类游戏, 每个客户端只能了解自己的手牌而不能知道其他人的牌.</strong></p>
<p><strong>让我们开发一个简单的猜骰子点数大小的游戏. 游戏分三个步骤:</strong></p>
<ul>
<li>玩家进入服务器房间, 服务器开始摇骰子出一个点数, 此时玩家虽然知道已摇出点数, 但是不能知道点数是多少;</li>
<li>玩家猜测点数大小并发送到服务器;</li>
<li>服务器开点数, 并把结果发回给客户端.</li>
</ul>
<p><img src="/assets/uploads/files/1673095159084-game-resized.jpg" alt="0_1673095144215_game.jpg" class="img-responsive img-markdown" /></p>
<p>点数 1~3 是 &quot;小&quot;, 4~6 是 &quot;大&quot;.</p>
<p><strong>游戏的 Schema 设定是关键所在:</strong></p>
<pre><code>import {Schema, Context, type, filter} from &quot;@colyseus/schema&quot;;
import {Client} from &quot;colyseus&quot;;

export class Dice extends Schema {
    @type(&quot;string&quot;) status: string = &quot;rolling&quot;;
    @type(&quot;string&quot;) result: string = &quot;&quot;;
    @filter(function (this: Dice, client: Client, value: Dice['number'], root: Schema) {
        return this.status == &quot;opened&quot;;
    })
    @type(&quot;uint8&quot;) number: number;

}
</code></pre>
<p><strong>首先导入 filter 装饰器, 才能使用. 这个游戏我们要过滤的是骰子点数, 也就是最后的 number. 过滤方法是看当前状态是否已经到了开点数的 status.<br />
status 分为 &quot;要骰子&quot;, &quot;猜点数&quot;, &quot;开点数&quot; 三个阶段.</strong></p>
<p><img src="/assets/uploads/files/1673095601682-filtered-resized.jpg" alt="0_1673095592433_filtered.jpg" class="img-responsive img-markdown" /></p>
<p><strong>&quot;猜点数&quot; 阶段虽然客户端知道有 &quot;number&quot; 这个数据, 但是值是 undefined.</strong></p>
<p><strong>当服务器在任何地方执行了 <code>this.state.status = &quot;opened&quot;;</code> 这条语句, 过滤自动失效, 此后客户端就能知道具体点数了.</strong></p>
<h2><img src="/assets/uploads/files/1673095867724-result-resized.jpg" alt="0_1673095858075_result.jpg" class="img-responsive img-markdown" /></h2>
<p><strong>代码和手册参考:</strong><br />
<a href="https://github.com/CocosGames/ColyseusFilters" rel="nofollow">https://github.com/CocosGames/ColyseusFilters</a><br />
<a href="https://docs.colyseus.io/colyseus/state/schema/#filtering-data-per-client" rel="nofollow">https://docs.colyseus.io/colyseus/state/schema/#filtering-data-per-client</a></p>
]]></description><link>http://discuss.colyseus.io/topic/876/colyseus-中的-filter</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Jul 2026 16:23:03 GMT</lastBuildDate><atom:link href="http://discuss.colyseus.io/topic/876.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 01 Jan 2023 11:16:49 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Colyseus 中的 &quot;Filter&quot; on Sat, 07 Jan 2023 17:52:54 GMT]]></title><description><![CDATA[<p><strong>Filter 是什么意思?<br />
Filter 这个词在检索和匹配类的程序中经常见到.<br />
比如下面这个网站.</strong></p>
<p><img src="/assets/uploads/files/1672746182786-00-resized.jpg" alt="0_1672746177268_00.jpg" class="img-responsive img-markdown" /></p>
<p><strong>Type to filter... 这里我们填写关键词,</strong></p>
<p><img src="/assets/uploads/files/1672746211795-01-resized.jpg" alt="0_1672746210946_01.jpg" class="img-responsive img-markdown" /></p>
<p><strong>匹配程序精准地帮我们找到了需要的内容.<br />
Colyseus 里面有两处与 Filter 有关的地方. 一个是 Matchmaking 用的 filterBy(); 一个是 Schema 用的 @filter 装饰器.</strong></p>
<hr />
<h3>RegisteredHandler.filterBy()</h3>
<p><strong>这次我们用 Colyseus Server + Cocos Creator Client 来做展示.</strong></p>
<p><strong>首先建立服务器环境.</strong></p>
<p><img src="/assets/uploads/files/1672914629293-19e93398-283a-41cb-8a16-49dd31537d5b-image-resized.png" alt="0_1672914626753_19e93398-283a-41cb-8a16-49dd31537d5b-image.png" class="img-responsive img-markdown" /></p>
<p><strong>不知道这个菜单哪里来的的话请</strong><a href="https://discuss.colyseus.io/topic/633/%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95-%E5%9C%A8%E6%AD%A4%E5%88%9B%E5%BB%BA-colyseus" rel="nofollow">参考这里</a>.</p>
<p><strong>新建 Cocos 项目, 安装 Colyseus 客户端 SDK.</strong></p>
<p><img src="/assets/uploads/files/1672746223880-1-resized.jpg" alt="0_1672746222679_1.jpg" class="img-responsive img-markdown" /></p>
<p><strong>如果发现导入时报错,</strong></p>
<p><img src="/assets/uploads/files/1672746233419-2-resized.jpg" alt="0_1672746232472_2.jpg" class="img-responsive img-markdown" /><br />
<strong>要在 tsconfig.json 文件中开启 <code>allowSyntheticDefaultImports</code> 参数.</strong></p>
<p><img src="/assets/uploads/files/1672746250841-3-resized.jpg" alt="0_1672746249762_3.jpg" class="img-responsive img-markdown" /><br />
<strong>好了, 准备工作结束, 让我们来连接房间看看.</strong></p>
<p><img src="/assets/uploads/files/1672747119488-5-resized.jpg" alt="0_1672747117496_5.jpg" class="img-responsive img-markdown" /></p>
<p><strong><code>joinOrCreate</code> 函数的第一个参数是房间名, 第二个参数是自定义的房间参数.<br />
这里我们自定义一个叫做 <code>mode</code> 的参数, 值为 <code>duo</code>, 表示是双人游戏房间.</strong></p>
<pre><code>this.room = await this.client.joinOrCreate(&quot;my_room&quot;, { mode: &quot;duo&quot; });
</code></pre>
<p><img src="/assets/uploads/files/1672746264391-4-resized.jpg" alt="0_1672746263798_4.jpg" class="img-responsive img-markdown" /></p>
<p><strong>在服务器端, 我们定义了房间名 my_room, 然后后面跟着一个 filterBy, 里面有两个过滤参数, &quot;mode&quot; 和 &quot;level&quot;.</strong></p>
<pre><code>gameServer.define('my_room', MyRoom).filterBy([&quot;mode&quot;, &quot;level&quot;]);

</code></pre>
<p><strong>它的意思是, 在进行房间匹配的时候, 把所有房间根据 &quot;mode&quot; 和 &quot;level&quot; 两个参数过滤, 只有这两个参数 <code>完全匹配</code> 的玩家才可以匹配进入相应房间.<br />
还记得客户端连接时的需求吗? 玩家要进入 &quot;mode&quot; 为 &quot;duo&quot; 的房间, &quot;level&quot; 没有指定.<br />
匹配器会根据 server 上已有的没有锁定的房间, 过滤出 &quot;mode&quot; 为 &quot;duo&quot; 的, &quot;level&quot; 为 null 的房间, 如果存在, 优先进入; 如果不存在, 新建一个这样的房间再进入.<br />
如果客户端没有要求参数, 如何匹配房间呢? 匹配器会寻找  &quot;mode&quot; 为 &quot;null&quot; 而且 &quot;level&quot; 为 &quot;null&quot; 的房间优先匹配进入; 对于 &quot;mode&quot; 为 &quot;duo&quot; 的房间, 它是 <code>不考虑在内</code> 的.<br />
除了 filterBy, 常用的还有一个 sortBy, 两个联合使用又是什么意思呢?</strong></p>
<pre><code>gameServer.define('my_room', MyRoom).filterBy([&quot;mode&quot;]).sortBy({level:-1});

</code></pre>
<p><strong>sortBy 的意思是排序. 根据参数值升序 (+) 或者降序 (-) 排序, 然后进行优先匹配.</strong><br />
<strong>上面那条语句的意思是, 寻找 mode 一致的, 按 level 从大到小排列, 选最大的, 进行匹配.</strong><br />
<strong>可以看出, filterBy 的作用就是告诉匹配器, 如何寻找, 找什么样的房间, 来给客户端进行分配.</strong></p>
<hr />
<h3>Schema 的  @filter 装饰器</h3>
<p><strong>众所周知(?), Schema 是会自动同步到房间的每一个客户端中的, 是 &quot;服务器权威&quot; 模式的基础.<br />
但是有时候, 我们需要某个客户端只能知道 Schema 的一部分而非全部.<br />
典型的需求就是牌类游戏, 每个客户端只能了解自己的手牌而不能知道其他人的牌.</strong></p>
<p><strong>让我们开发一个简单的猜骰子点数大小的游戏. 游戏分三个步骤:</strong></p>
<ul>
<li>玩家进入服务器房间, 服务器开始摇骰子出一个点数, 此时玩家虽然知道已摇出点数, 但是不能知道点数是多少;</li>
<li>玩家猜测点数大小并发送到服务器;</li>
<li>服务器开点数, 并把结果发回给客户端.</li>
</ul>
<p><img src="/assets/uploads/files/1673095159084-game-resized.jpg" alt="0_1673095144215_game.jpg" class="img-responsive img-markdown" /></p>
<p>点数 1~3 是 &quot;小&quot;, 4~6 是 &quot;大&quot;.</p>
<p><strong>游戏的 Schema 设定是关键所在:</strong></p>
<pre><code>import {Schema, Context, type, filter} from &quot;@colyseus/schema&quot;;
import {Client} from &quot;colyseus&quot;;

export class Dice extends Schema {
    @type(&quot;string&quot;) status: string = &quot;rolling&quot;;
    @type(&quot;string&quot;) result: string = &quot;&quot;;
    @filter(function (this: Dice, client: Client, value: Dice['number'], root: Schema) {
        return this.status == &quot;opened&quot;;
    })
    @type(&quot;uint8&quot;) number: number;

}
</code></pre>
<p><strong>首先导入 filter 装饰器, 才能使用. 这个游戏我们要过滤的是骰子点数, 也就是最后的 number. 过滤方法是看当前状态是否已经到了开点数的 status.<br />
status 分为 &quot;要骰子&quot;, &quot;猜点数&quot;, &quot;开点数&quot; 三个阶段.</strong></p>
<p><img src="/assets/uploads/files/1673095601682-filtered-resized.jpg" alt="0_1673095592433_filtered.jpg" class="img-responsive img-markdown" /></p>
<p><strong>&quot;猜点数&quot; 阶段虽然客户端知道有 &quot;number&quot; 这个数据, 但是值是 undefined.</strong></p>
<p><strong>当服务器在任何地方执行了 <code>this.state.status = &quot;opened&quot;;</code> 这条语句, 过滤自动失效, 此后客户端就能知道具体点数了.</strong></p>
<h2><img src="/assets/uploads/files/1673095867724-result-resized.jpg" alt="0_1673095858075_result.jpg" class="img-responsive img-markdown" /></h2>
<p><strong>代码和手册参考:</strong><br />
<a href="https://github.com/CocosGames/ColyseusFilters" rel="nofollow">https://github.com/CocosGames/ColyseusFilters</a><br />
<a href="https://docs.colyseus.io/colyseus/state/schema/#filtering-data-per-client" rel="nofollow">https://docs.colyseus.io/colyseus/state/schema/#filtering-data-per-client</a></p>
]]></description><link>http://discuss.colyseus.io/post/2296</link><guid isPermaLink="true">http://discuss.colyseus.io/post/2296</guid><dc:creator><![CDATA[COCO]]></dc:creator><pubDate>Sat, 07 Jan 2023 17:52:54 GMT</pubDate></item></channel></rss>