Skip to content

狀態數據同步 » Schema

還沒使用 TypeScript?

強烈建議您使用 TypeScript 以便更好地定義 Schema 結構並提高整體開發體驗. TypeScript 支持的 "實驗性修飾器" 會在本手冊內大量使用.

如何定義可同步結構

  • Schema 結構由服務器定義, 用於房間狀態服務端客戶端數據同步.
  • 只有以 @type() 修飾的字段才會被用於同步.
  • (可同步 Schema 結構僅應被用於需要服務器客戶端同步的數據.)

定義 Schema 結構

// MyState.ts
import { Schema, type } from "@colyseus/schema";

export class MyState extends Schema {
    @type("string") currentTurn: string;
}
// MyState.ts
const schema = require('@colyseus/schema');
const Schema = schema.Schema;

class MyState extends Schema {
}
schema.defineTypes(MyState, {
  currentTurn: "string"
});

"這個 @type() 關鍵字是什麽? 我之前從未見過!"

您看見的在本頁大量使用的 @type() 是一個即將推出的 JavaScript 功能, 還沒有被 TC39 正式認可. type 其實只是一個從 @colyseus/schema 模塊導入的函數. 在屬性層級調用帶有 @ 前綴的 type, 意味著我們將其作為一個 屬性修飾器 進行調用. 在這裏查看修飾器方案.

在您的 Room 內使用狀態

// MyRoom.ts
import { Room } from "colyseus";
import { MyState } from "./MyState";

export class MyRoom extends Room<MyState> {
    onCreate() {
        this.setState(new MyState());
    }
}

使用 Schema

  • 只有服務器端有權修改 Schema 數據
  • 客戶端要包含用 schema-codegen 生成的, 與服務器端相一致的 Schema 定義. (如果使用 JavaScript SDK 則此條為可選項)
  • 為了從服務器獲得更新, 需要 在客戶端把回調附加在 schema 實例上.
  • 客戶端永遠不應主動修改 schema - 因為在收到來自服務器的下一幀更新時就會把它覆蓋掉.

基本類型

基本類型為數字, 字符串和布爾型.

類型 描述 範圍
"string" utf8 字符串 最大 4294967295 字節
"number" 又稱為 "正整數". 自動檢測數字類型. (編碼時可能會多用1個字節) 取值範圍 018446744073709551615
"boolean" truefalse 取值為 01

特定數值類型:

類型 描述 範圍
"int8" 有符號 8-bit 整數 -128127
"uint8" 無符號 8-bit 整數 0255
"int16" 有符號 16-bit 整數 -3276832767
"uint16" 無符號 16-bit 整數 065535
"int32" 有符號 32-bit 整數 -21474836482147483647
"uint32" 無符號 32-bit 整數 04294967295
"int64" 有符號 64-bit 整數 -92233720368547758089223372036854775807
"uint64" 無符號 64-bit 整數 018446744073709551615
"float32" 單精度浮點數 -3.40282347e+383.40282347e+38
"float64" 雙精度浮點數 -1.7976931348623157e+3081.7976931348623157e+308

復雜類型

復雜類型由 Schema 嵌套而成. 它們也可以包含 集合類型 (array, map 等).

import { Schema, type } from "@colyseus/schema";

class World extends Schema {
    @type("number") width: number;
    @type("number") height: number;
    @type("number") items: number = 10;
}

class MyState extends Schema {
    @type(World) world: World = new World();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;

class World extends Schema {
}
schema.defineTypes(World, {
  width: "number",
  height: "number",
  items: "number"
});

class MyState extends Schema {
    constructor () {
        super();

        this.world = new World();
    }
}
schema.defineTypes(MyState, {
  world: World
});

集合類型

ArraySchema

ArraySchema 是 JavaScript 內置 Array 類型的一種可同步版本.

示例: 自定義 Schema 類型 數組

import { Schema, ArraySchema, type } from "@colyseus/schema";

class Block extends Schema {
    @type("number") x: number;
    @type("number") y: number;
}

class MyState extends Schema {
    @type([ Block ]) blocks = new ArraySchema<Block>();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;
const ArraySchema = schema.ArraySchema;

class Block extends Schema {
}
schema.defineTypes(Block, {
  x: "number",
  y: "number"
});

class MyState extends Schema {
    constructor () {
        super();

        this.blocks = new ArraySchema();
    }
}
schema.defineTypes(MyState, {
  blocks: [ Block ],
});

示例: 基本類型數組

數組元素必須是同一數據類型.

import { Schema, ArraySchema, type } from "@colyseus/schema";

class MyState extends Schema {
    @type([ "string" ]) animals = new ArraySchema<string>();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;
const ArraySchema = schema.ArraySchema;

class MyState extends Schema {
    constructor () {
        super();

        this.animals = new ArraySchema();
    }
}
schema.defineTypes(MyState, {
  animals: [ "string" ],
});

array.push()

在一個數組後面添加一個或多個元素, 並返回該數組更新後的長度.

const animals = new ArraySchema<string>();
animals.push("pigs", "goats");
animals.push("sheeps");
animals.push("cows");
// 輸出: 4


array.pop()

移除一個數組的最後一個元素並返回該元素. 該方法會改變數組的長度.

animals.pop();
// 輸出: "cows"

animals.length
// 輸出: 3


array.shift()

移除一個數組的第一個元素並返回該元素. 該方法會改變數組的長度.

animals.shift();
// 輸出: "pigs"

animals.length
// 輸出: 2


array.unshift()

在一個數組的開頭添加一個或多個元素, 並返回該數組更新後的長度.

animals.unshift("pigeon");
// 輸出: 3


array.indexOf()

返回數組中找到給定元素的第一個索引, 如果不存在則返回 -1

const itemIndex = animals.indexOf("sheeps");


array.splice()

移除替換現有元素或 在指定位置 添加新元素來更改一個數組的內容.

// 找到需要移除元素的索引
const itemIndex = animals.findIndex((animal) => animal === "sheeps");

// 移除元素!
animals.splice(itemIndex, 1);


array.forEach()

叠代數組的每個元素.

this.state.array1 = new ArraySchema<string>('a', 'b', 'c');

this.state.array1.forEach(element => {
    console.log(element);
});
// 輸出: "a"
// 輸出: "b"
// 輸出: "c"
State.array1.ForEach((value) => {
    Debug.Log(value);
})
state.array1:each(function(value, index)
    print(index, "=>")
    pprint(value)
end)
for (index => value in state.array1) {
    trace(index + " => " + value);
}

Array 還有更多函數可用

詳見 MDN 文檔.

MapSchema

MapSchema 是基於 JavaScript 內置 Map 的一種可同步版本.

推薦使用 Maps 裏的 id 來追蹤遊戲實體, 比如玩家, 敵人等.

當前僅支持字符串類型的 id

目前, MapSchema 允許您自定義值的類型, 但是鍵的類型必須為為 string.

import { Schema, MapSchema, type } from "@colyseus/schema";

class Player extends Schema {
    @type("number") x: number;
    @type("number") y: number;
}

class MyState extends Schema {
    @type({ map: Player }) players = new MapSchema<Player>();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;
const MapSchema = schema.MapSchema;

class Player extends Schema {
}
schema.defineTypes(Player, {
  x: "number",
  y: "number"
});

class MyState extends Schema {
    constructor () {
        super();

        this.players = new MapSchema();
    }
}
schema.defineTypes(MyState, {
  players: { map: Player }
});

map.get()

通過鍵得到 map 的值:

const map = new MapSchema<string>();
const item = map.get("key");


map.set()

通過鍵來設置 map 的值:

const map = new MapSchema<string>();
map.set("key", "value");


map.delete()

通過鍵移除 map 的值:

map.delete("key");


map.size

返回 MapSchema 對象中元素的數量.

const map = new MapSchema<number>();
map.set("one", 1);
map.set("two", 2);

console.log(map.size);
// 輸出: 2


map.forEach()

以元素插入順序叠代 map 中的鍵值對.

this.state.players.forEach((value, key) => {
    console.log("key =>", key)
    console.log("value =>", value)
});
State.players.ForEach((key, value) => {
    Debug.Log(key);
    Debug.Log(value);
})
state.players:each(function(value, key)
    print(key, "=>")
    pprint(value)
end)
for (key => value in state.players) {
    trace(index + " => " + value);
}

Map 還有更多函數可用

詳見 MDN 文檔.

SetSchema

SetSchema 僅支持 JavaScript

目前 SetSchema 只能在 JavaScript 中使用. 尚不支持 Haxe, C#, LUA 和 C++ 客戶端.

SetSchema 是一個基於 JavaScript 內置 Set 的可同步版本.

SetSchema 的用法和 [CollectionSchema] 十分類似, 最大區別在於 Set 的值具有唯一性. Set 沒有直接獲取值的方法. (比如像 collection.at())

import { Schema, SetSchema, type } from "@colyseus/schema";

class Effect extends Schema {
    @type("number") radius: number;
}

class Player extends Schema {
    @type({ set: Effect }) effects = new SetSchema<Effect>();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;
const SetSchema = schema.SetSchema;

class Effect extends Schema {
}
schema.defineTypes(Effect, {
  radius: "number",
});

class Player extends Schema {
    constructor () {
        super();

        this.effects = new SetSchema();
    }
}
schema.defineTypes(Player, {
  effects: { set: Effect }
});

set.add()

SetSchema 添加元素.

const set = new SetSchema<number>();
set.add(1);
set.add(2);
set.add(3);


set.delete()

按值刪除元素.

set.delete("three");


set.has()

檢查集合中是否有該值.

if (set.has("two")) {
    console.log("Exists!");
} else {
    console.log("Does not exist!");
}


set.size

返回 SetSchema 裏元素的長度.

const set = new SetSchema<number>();
set.add(10);
set.add(20);
set.add(30);

console.log(set.size);
// 輸出: 3

Set 還有更多函數可用

詳見 MDN 文檔.

CollectionSchema

CollectionSchema 僅支持 JavaScript

目前 CollectionSchema 只能在 JavaScript 中使用. 尚不支持 Haxe, C#, LUA 和 C++ 客戶端.

CollectionSchema 的用法與 ArraySchema 類似, 需要註意的是, 它不具備某些數組可用的函數.

import { Schema, CollectionSchema, type } from "@colyseus/schema";

class Item extends Schema {
    @type("number") damage: number;
}

class Player extends Schema {
    @type({ collection: Item }) items = new CollectionSchema<Item>();
}
const schema = require('@colyseus/schema');
const Schema = schema.Schema;
const CollectionSchema = schema.CollectionSchema;

class Item extends Schema {
}
schema.defineTypes(Item, {
  damage: "number",
});

class Player extends Schema {
    constructor () {
        super();

        this.items = new CollectionSchema();
    }
}
schema.defineTypes(Player, {
  items: { collection: Item }
});

collection.add()

CollectionSchema 添加元素.

const collection = new CollectionSchema<number>();
collection.add(1);
collection.add(2);
collection.add(3);


collection.at()

獲取 index 處的值.

const collection = new CollectionSchema<string>();
collection.add("one");
collection.add("two");
collection.add("three");

collection.at(1);
// 輸出: "two"


collection.delete()

按值刪除元素.

collection.delete("three");


collection.has()

檢查集合中是否有該值.

if (collection.has("two")) {
    console.log("Exists!");
} else {
    console.log("Does not exist!");
}


collection.size

返回 CollectionSchema 裏元素的長度.

const collection = new CollectionSchema<number>();
collection.add(10);
collection.add(20);
collection.add(30);

console.log(collection.size);
// 輸出: 3


collection.forEach()

叠代 CollectionSchema 中的鍵值對, 以元素插入順序.

collection.forEach((value, at) => {
    console.log("at =>", at)
    console.log("value =>", value)
});

按客戶端過濾數據

此功能為實驗性質

@filter() / @filterChildren() 為實驗性質, 可能不適合快節奏遊戲.

過濾用來為指定客戶端隱藏部分狀態數據, 防止作弊, 防止玩家獲取全部數據.

數據過濾器回調, 可以針對 每個客戶端每個字段 進行觸發 (如果使用了 @filterChildren, 還可針對每個子結構觸發). 如果過濾器回調返回 true, 則該字段數據將會發送給那個指定的客戶端, 否則不發送.

請註意, 只有被過濾字段 (或其子字段) 數據更新時, 過濾器回調才能被觸發. 要想手動觸發請參考 此問題 裏描述的方法.

@filter() 屬性修飾器

@filter() 屬性修飾器可作用於整個 Schema 字段.

下面展示了 @filter() 的函數簽名:

class State extends Schema {
    @filter(function(client, value, root) {
        // client 參數是:
        //
        // 當前將要接受數據的客戶端. 可以通過其
        // client.sessionId, 及其他信息判定是否
        // 要把數據同步給這個客戶端.

        // value 參數是:
        // 被 @filter() 標記過濾的字段值

        // root 參數是:
        // 房間 Schema 實例引用. 方便在是否過濾的
        // 決策過程中
        // 訪問房間狀態.
    })
    @type("string") field: string;
}
const schema = require('@colyseus/schema');
class State extends schema.Schema {}

schema.defineTypes(State, {
    field: "string"
});

schema.filter(function(client, value, root) {
    // client 參數是:
    //
    // 當前將要接受數據的客戶端. 可以通過其
    // client.sessionId, 及其他信息判定是否
    // 要把數據同步給這個客戶端.

    // value 參數是:
    // 被 @filter() 標記過濾的字段值

    // root 參數是:
    // 房間 Schema 實例引用. 方便在是否過濾的
    // 決策過程中
    // 訪問房間狀態.
    return true;
})(State.prototype, "field");

@filterChildren() 屬性修飾器

@filterChildren() 屬性修飾器可用於過濾掉 array, map, set等集合類型的內容. 它的簽名與 @filter() 基本相同, 但是在 value 之前添加了 key 參數 - 表示 ArraySchema, MapSchema, CollectionSchema 等內容的索引.

class State extends Schema {
    @filterChildren(function(client, key, value, root) {
        // client 參數是:
        //
        // 當前將要接受數據的客戶端. 可以通過其
        // client.sessionId, 及其他信息判定是否
        // 要把數據同步給這個客戶端.

        // key 參數是:
        // 集合內容的當前索引

        // value 參數是:
        // 集合內容當前索引處的值

        // root 參數是:
        // 房間 Schema 實例引用. 方便在是否過濾的
        // 決策過程中
        // 訪問房間狀態.
    })
    @type([Cards]) cards = new ArraySchema<Card>();
}
const schema = require('@colyseus/schema');
class State extends schema.Schema {}

schema.defineTypes(State, {
    cards: [Card]
});

schema.filterChildren(function(client, key, value, root) {
    // client 參數是:
    //
    // 當前將要接受數據的客戶端. 可以通過其
    // client.sessionId, 及其他信息判定是否
    // 要把數據同步給這個客戶端.

    // key 參數是:
    // 集合內容的當前索引

    // value 參數是:
    // 集合內容當前索引處的值

    // root 參數是:
    // 房間 Schema 實例引用. 方便在是否過濾的
    // 決策過程中
    // 訪問房間狀態.
    return true;
})(State.prototype, "cards");

示例: 在卡牌遊戲中, 應該只有卡牌的持有者知道每個卡片的數據, 或者在特定條件下才能知道這些數據 (例如攤牌)

參考 @filter() 回調簽名:

import { Client } from "colyseus";

class Card extends Schema {
    @type("string") owner: string; // 用來保存卡牌持有者的 sessionId
    @type("boolean") discarded: boolean = false;

    /**
     * 不要在 `@filter` 函數裏使用箭頭函數
     * (會造成 `this` 指針丟失)
     */
    @filter(function(
        this: Card, // 定義 `@filter` 的類 (這裏 this 就是 `Card` 的實例)
        client: Client, // 要被過濾的客戶端 `client` 實例
        value: Card['number'], // 要被過濾的字段值. (這裏是 `number` 字段的值)
        root: Schema // 房間狀態 Schema 實例
    ) {
        return this.discarded || this.owner === client.sessionId;
    })
    @type("uint8") number: number;
}
const schema = require('@colyseus/schema');

class Card extends schema.Schema {}
schema.defineTypes(Card, {
    owner: "string",
    discarded: "boolean",
    number: "uint8"
});

/**
 * 不要在 `@filter` 函數裏使用箭頭函數
 * (會造成 `this` 指針丟失)
 */
schema.filter(function(client, value, root) {
    return this.discarded || this.owner === client.sessionId;
})(Card.prototype, "number");

客戶端

C#, C++, Haxe

在使用強類型語言時, 需要基於 Typescript schema 定義手動生成客戶端 schema 文件. 生成客戶端 schema 的方法.

回調

服務器狀態數據更新應用到客戶端時, 會根據變更的類型自動觸發本地實例上的回調.

回調通過房間狀態實例觸發. 使用前要確保該實例上已實現回調函數.

.listen(prop, callback)

偵聽單個屬性更新.

參數:

  • property: 想要偵聽更新的屬性名稱.
  • callback: 當 property 更新時觸發的回調.
state.listen("currentTurn", (currentValue, previousValue) => {
    console.log(`currentTurn is now ${currentValue}`);
    console.log(`previous value was: ${previousValue}`);
});
state.OnCurrentTurnChange((currentValue, previousValue) => {
    Debug.Log(currentValue);
    Debug.Log(previousValue);
})
state:listen("currentTurn", function (current_value, previous_value)
    pprint(current_value);
    pprint(previous_value);
end)
state.listen("currentTurn", (currentValue, previousValue) => {
    trace(currentValue);
    trace(previousValue);
});

.listen() 返回的句柄可用於移除偵聽器

const removeListener = state.listen("currentTurn", (currentValue, previousValue) => {
    // ...
});

// 之後, 如果不需要偵聽器了, 可以調用 `removeListener()` 來移除對 `"currentTurn"` 的偵聽.
removeListener();

listenonChange 有什麽區別?

.listen() 方法是專為監聽單個屬性的 onChange 的簡化版本. 下面是把 .listen() 寫成 onChange 的樣子:

state.onChange = function(changes) {
    changes.forEach((change) => {
        if (change.field === "currentTurn") {
            console.log(`currentTurn is now ${change.value}`);
            console.log(`previous value was: ${change.previousValue}`);
        }
    })
}


onAdd (instance, key)

只有集合 (MapSchema, ArraySchema 等) 可以使用 onAdd 回調. 集合更新後觸發 onAdd 回調, 外加已更新內容的鍵作為參數.

room.state.players.onAdd((player, key) => {
    console.log(player, "has been added at", key);

    // 在遊戲中加入player!

    // 要想跟蹤地圖上物體的移動, 通常要這麽做:
    player.onChange(function(changes) {
        changes.forEach(change => {
            console.log(change.field);
            console.log(change.value);
            console.log(change.previousValue);
        })
    });
});
room.state.players:on_add(function (player, key)
    print("player has been added at", key);

    -- 在遊戲中加入player!

    -- 要想跟蹤地圖上物體的移動, 通常要這麽做:
    player:on_change(function(changes)
        for i, change in ipairs(changes) do
            print(change.field)
            print(change.value)
            print(change.previousValue)
        end
    end)
end)
room.State.players.OnAdd((string key, Player player) =>
{
    Debug.Log("player has been added at " + key);

    // 在遊戲中加入player!

    // 要想跟蹤地圖上物體的移動, 通常要這麽做:
    player.OnChange += (changes) =>
    {
        changes.ForEach((obj) =>
        {
            Debug.Log(obj.Field);
            Debug.Log(obj.Value);
            Debug.Log(obj.PreviousValue);
        });
    };
});

onRemove (instance, key)

只有映射 (MapSchema) 和數組 (ArraySchema) 可以使用 onRemove 回調. 集合更新後觸發 onRemove 回調, 外加已移除內容的鍵作為參數.

room.state.players.onRemove((player, key) => {
    console.log(player, "has been removed at", key);

    // 從遊戲中移除player!
});
room.state.players:on_remove(function (player, key)
    print("player has been removed at " .. key);

    -- 從遊戲中移除player!
end)
room.State.players.OnRemove((string key, Player player) =>
{
    Debug.Log("player has been removed at " + key);

    // 從遊戲中移除player!
});

onChange (changes:DataChange[])

Schema 上的 onChange 和集合上的不一樣. 對於 集合結構(數組, 映射等)的 onChange 請參考這裏.

可以註冊 onChange 以跟蹤 Schema 實例屬性的變更. onChange 的參數數組包含已變更的屬性以及變更前的值.

room.state.onChange((changes) => {
    changes.forEach(change => {
        console.log(change.field);
        console.log(change.value);
        console.log(change.previousValue);
    });
};
room.state:on_change(function (changes)
    for i, change in ipairs(changes) do
        print(change.field)
        print(change.value)
        print(change.previous_value)
    end
end)
room.State.OnChange((changes) =>
{
    changes.ForEach((obj) =>
    {
        Debug.Log(obj.Field);
        Debug.Log(obj.Value);
        Debug.Log(obj.PreviousValue);
    });
};

沒與客戶端同步過的狀態上不能註冊 onChange 回調.


onChange (instance, key)

Schema 上的 onChange 和集合上的不一樣. 對於 SchemaonChange 請參考這裏.

當集合裏的 基本 類型 (string, number, boolean 等) 值更新時, 將觸發此回調.

room.state.players.onChange((player, key) => {
    console.log(player, "have changes at", key);
};
room.state.players:on_change(function (player, key)
    print("player have changes at " .. key);
end)
room.State.players.OnChange((string key, Player player) =>
{
    Debug.Log("player have changes at " + key);
});

對於 非基本 類型 (各種 Schema 集合), 請先註冊 onAdd 再註冊 onChange.

onChange, onAddonRemove互斥的

onChange 回調在 onAddonRemove 期間不會被觸發.

如果想要跟蹤的更新包括 onAddonRemove, 請註冊這兩個回調.


生成客戶端 schema 的方法

schema-codegen 是一個轉譯工具, 用於把服務器端的 schema 定義文件轉換為客戶端可以使用的版本:

要在客戶端正確解碼 state, 客戶端的 schema 定義文件必須與服務器端相兼容.

在使用 JavaScript SDK 時不必使用此工具

只有在客戶端使用強類型語言, 如 C#, Haxe 等時, 才必須使用 schema-codegen.

使用方法

要在終端查看使用方法, 先 cd 進入服務器目錄, 然後運行以下命令:

npx schema-codegen --help

輸出:

schema-codegen [path/to/Schema.ts]

Usage (C#/Unity)
    schema-codegen src/Schema.ts --output client-side/ --csharp --namespace MyGame.Schema

Valid options:
    --output: fhe output directory for generated client-side schema files
    --csharp: generate for C#/Unity
    --cpp: generate for C++
    --haxe: generate for Haxe
    --ts: generate for TypeScript
    --js: generate for JavaScript
    --java: generate for Java

Optional:
    --namespace: generate namespace on output code

舉例: Unity / C

下面是用 Unity 演示項目 生成 C# schema 文件的實例.

npx schema-codegen src/rooms/schema/* --csharp --output ../Assets/Scripts/States/"
generated: Player.cs
generated: State.cs

使用 npm 腳本:

方便起見, 推薦您把 schema-codegen 的參數保存在 package.json 文件中的 npm 腳本裏:

"scripts": {
    "schema-codegen": "schema-codegen src/rooms/schema/* --csharp --output ../Assets/Scripts/States/"
}

這樣, 運行 npm run schema-codegen, 就可以代替完整的命令:

npm run schema-codegen
generated: Player.cs
generated: State.cs

版本及向下/向上兼容

通過在現有結構末尾聲明新字段, 可以實現向下/向上兼容, 不應刪除先前的聲明, 而是應該根據需要將其標記為 @deprecated(). 下面是一個例子.

import { Schema, type, deprecated } from "@colyseus/schema";

class MyState extends Schema {
    @type("string") myField: string;
}
import { Schema, type, deprecated } from "@colyseus/schema";

class MyState extends Schema {
    // 標記此字段作廢.
    @deprecated() @type("string") myField: string;

    // 保證不同客戶端版本的服務器兼容.
    @type("string") newField: string;
}
import { Schema, type, deprecated } from "@colyseus/schema";

class MyState extends Schema {
    // 標記此字段作廢.
    @deprecated() @type("string") myField: string;

    // 再次標記此字段作廢.
    @deprecated() @type("string") newField: string;

    // 最新的字段總是保持在最下邊
    @type("string") anotherNewField: string;
}

這對於本地編譯類語言很有用, 如 C#, C++, Haxe 等 - 即使這些客戶端編譯時沒有最新的 schema 定義.


限製和最佳實踐

  • 每個 Schema 結構最多可以保存 64 個字段. 如果需要更多字段, 可以嵌套使用 Schema 結構.
  • NaNnull 數字被編碼為 0
  • null 字符串被編碼為 ""
  • Infinity 數字被編碼為 Number.MAX_SAFE_INTEGER
  • 不支持多維數組. 查看如何將一維數組作為多維數組使用
  • @colyseus/schema 編碼順序按照字段定義順序.
    • 編碼器 (服務器) 和解碼器 (客戶端) 都必須擁有相同的 schema 定義.
    • 字段的順序也要相同.

集合

集合類型 (ArraySchema, MapSchema 等) 裏的元素類型必須相同, 或者基類相同.

支持以下寫法:

class Item extends Schema {/* 基類 Item */}
class Weapon extends Item {/* 武器類 */}
class Shield extends Item {/* 盾牌類 */}

class Inventory extends Schema {
    @type({ map: Item }) items = new MapSchema<Item>();
}

const inventory = new Inventory();
inventory.set("left", new Weapon());
inventory.set("right", new Shield());

Back to top