baxi 1 månad sedan
incheckning
f73ddb495d
100 ändrade filer med 14623 tillägg och 0 borttagningar
  1. 26 0
      .gitignore
  2. 9 0
      assets/colyseus.meta
  3. 5359 0
      assets/colyseus/colyseus-cocos-creator.js
  4. 17 0
      assets/colyseus/colyseus-cocos-creator.js.meta
  5. 774 0
      assets/colyseus/colyseus.d.ts
  6. 9 0
      assets/colyseus/colyseus.d.ts.meta
  7. 11 0
      assets/lobbyRes.meta
  8. 9 0
      assets/lobbyRes/scenes.meta
  9. 795 0
      assets/lobbyRes/scenes/Game.scene
  10. 11 0
      assets/lobbyRes/scenes/Game.scene.meta
  11. 1518 0
      assets/lobbyRes/scenes/Lobby.scene
  12. 11 0
      assets/lobbyRes/scenes/Lobby.scene.meta
  13. 9 0
      assets/lobbyRes/textures.meta
  14. 9 0
      assets/lobbyRes/textures/loading.meta
  15. BIN
      assets/lobbyRes/textures/loading/img_loading.png
  16. 134 0
      assets/lobbyRes/textures/loading/img_loading.png.meta
  17. 9 0
      assets/lobbyRes/ui.meta
  18. 9 0
      assets/lobbyRes/ui/home.meta
  19. 1025 0
      assets/lobbyRes/ui/home/HomeView.prefab
  20. 14 0
      assets/lobbyRes/ui/home/HomeView.prefab.meta
  21. 9 0
      assets/lobbyRes/ui/loading.meta
  22. 476 0
      assets/lobbyRes/ui/loading/LoadingView.prefab
  23. 13 0
      assets/lobbyRes/ui/loading/LoadingView.prefab.meta
  24. 9 0
      assets/lobbyRes/ui/login.meta
  25. 839 0
      assets/lobbyRes/ui/login/LoginView.prefab
  26. 14 0
      assets/lobbyRes/ui/login/LoginView.prefab.meta
  27. 14 0
      assets/resources.meta
  28. 9 0
      assets/scenes.meta
  29. 986 0
      assets/scenes/Launch.scene
  30. 11 0
      assets/scenes/Launch.scene.meta
  31. 587 0
      assets/scenes/Test.scene
  32. 11 0
      assets/scenes/Test.scene.meta
  33. 9 0
      assets/scripts.meta
  34. 23 0
      assets/scripts/Test.ts
  35. 9 0
      assets/scripts/Test.ts.meta
  36. 9 0
      assets/scripts/api.meta
  37. 18 0
      assets/scripts/api/Config.ts
  38. 9 0
      assets/scripts/api/Config.ts.meta
  39. 29 0
      assets/scripts/api/LobbyApi.ts
  40. 9 0
      assets/scripts/api/LobbyApi.ts.meta
  41. 37 0
      assets/scripts/api/LoginApi.ts
  42. 9 0
      assets/scripts/api/LoginApi.ts.meta
  43. 41 0
      assets/scripts/api/PaymentApi.ts
  44. 9 0
      assets/scripts/api/PaymentApi.ts.meta
  45. 29 0
      assets/scripts/api/WalletApi.ts
  46. 9 0
      assets/scripts/api/WalletApi.ts.meta
  47. 5 0
      assets/scripts/api/index.ts
  48. 9 0
      assets/scripts/api/index.ts.meta
  49. 9 0
      assets/scripts/app.meta
  50. 22 0
      assets/scripts/app/AppConfig.ts
  51. 9 0
      assets/scripts/app/AppConfig.ts.meta
  52. 22 0
      assets/scripts/app/AppEvents.ts
  53. 9 0
      assets/scripts/app/AppEvents.ts.meta
  54. 87 0
      assets/scripts/app/AppKernel.ts
  55. 9 0
      assets/scripts/app/AppKernel.ts.meta
  56. 9 0
      assets/scripts/components.meta
  57. 9 0
      assets/scripts/constants.meta
  58. 7 0
      assets/scripts/constants/Localkey.ts
  59. 9 0
      assets/scripts/constants/Localkey.ts.meta
  60. 9 0
      assets/scripts/define.meta
  61. 9 0
      assets/scripts/define/AppConfig.ts.meta
  62. 14 0
      assets/scripts/define/Define.ts
  63. 9 0
      assets/scripts/define/Define.ts.meta
  64. 3 0
      assets/scripts/define/ResDefine.ts
  65. 9 0
      assets/scripts/define/ResDefine.ts.meta
  66. 44 0
      assets/scripts/define/UIDefine.ts
  67. 9 0
      assets/scripts/define/UIDefine.ts.meta
  68. 9 0
      assets/scripts/framework.meta
  69. 9 0
      assets/scripts/framework/event.meta
  70. 74 0
      assets/scripts/framework/event/EventManager.ts
  71. 9 0
      assets/scripts/framework/event/EventManager.ts.meta
  72. 9 0
      assets/scripts/framework/resource.meta
  73. 78 0
      assets/scripts/framework/resource/ResourceManager.ts
  74. 9 0
      assets/scripts/framework/resource/ResourceManager.ts.meta
  75. 9 0
      assets/scripts/framework/scene.meta
  76. 72 0
      assets/scripts/framework/scene/SceneNavigator.ts
  77. 9 0
      assets/scripts/framework/scene/SceneNavigator.ts.meta
  78. 9 0
      assets/scripts/framework/state.meta
  79. 69 0
      assets/scripts/framework/state/AsyncStateMachine.ts
  80. 9 0
      assets/scripts/framework/state/AsyncStateMachine.ts.meta
  81. 9 0
      assets/scripts/framework/ui.meta
  82. 36 0
      assets/scripts/framework/ui/UILayer.ts
  83. 9 0
      assets/scripts/framework/ui/UILayer.ts.meta
  84. 339 0
      assets/scripts/framework/ui/UIManager.ts
  85. 9 0
      assets/scripts/framework/ui/UIManager.ts.meta
  86. 45 0
      assets/scripts/framework/ui/UIView.ts
  87. 9 0
      assets/scripts/framework/ui/UIView.ts.meta
  88. 9 0
      assets/scripts/modules.meta
  89. 9 0
      assets/scripts/modules/game.meta
  90. 71 0
      assets/scripts/modules/game/GameController.ts
  91. 9 0
      assets/scripts/modules/game/GameController.ts.meta
  92. 110 0
      assets/scripts/modules/game/WebViewHandler.ts
  93. 9 0
      assets/scripts/modules/game/WebViewHandler.ts.meta
  94. 9 0
      assets/scripts/modules/launch.meta
  95. 163 0
      assets/scripts/modules/launch/LaunchController.ts
  96. 9 0
      assets/scripts/modules/launch/LaunchController.ts.meta
  97. 59 0
      assets/scripts/modules/launch/LaunchStateMachine.ts
  98. 9 0
      assets/scripts/modules/launch/LaunchStateMachine.ts.meta
  99. 9 0
      assets/scripts/modules/launch/states.meta
  100. 12 0
      assets/scripts/modules/launch/states/CheckVersionState.ts

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+
+#///////////////////////////
+# Cocos Creator 3D Project
+#///////////////////////////
+library/
+temp/
+local/
+build/
+profiles/
+native/engine/common
+#//////////////////////////
+# NPM
+#//////////////////////////
+node_modules/
+
+#//////////////////////////
+# VSCode
+#//////////////////////////
+.vscode/
+
+#//////////////////////////
+# WebStorm
+#//////////////////////////
+.idea/
+
+.gradle

+ 9 - 0
assets/colyseus.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "ae2479fe-042f-4b7a-a1fc-0332be9ad217",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 5359 - 0
assets/colyseus/colyseus-cocos-creator.js

@@ -0,0 +1,5359 @@
+// THIS VERSION USES "XMLHttpRequest" INSTEAD OF "fetch" FOR COMPATIBILITY WITH COCOS CREATOR
+// colyseus.js@0.15.25 (@colyseus/schema 2.0.9)
+(function (global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+    typeof define === 'function' && define.amd ? define('colyseus.js', ['exports'], factory) :
+    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Colyseus = {}));
+})(this, (function (exports) { 'use strict';
+
+    function _mergeNamespaces(n, m) {
+        m.forEach(function (e) {
+            e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
+                if (k !== 'default' && !(k in n)) {
+                    var d = Object.getOwnPropertyDescriptor(e, k);
+                    Object.defineProperty(n, k, d.get ? d : {
+                        enumerable: true,
+                        get: function () { return e[k]; }
+                    });
+                }
+            });
+        });
+        return Object.freeze(n);
+    }
+
+    //
+    // Polyfills for legacy environments
+    //
+    /*
+     * Support Android 4.4.x
+     */
+    if (!ArrayBuffer.isView) {
+        ArrayBuffer.isView = function (a) {
+            return a !== null && typeof (a) === 'object' && a.buffer instanceof ArrayBuffer;
+        };
+    }
+    // Define globalThis if not available.
+    // https://github.com/colyseus/colyseus.js/issues/86
+    if (typeof (globalThis) === "undefined" &&
+        typeof (window) !== "undefined") {
+        // @ts-ignore
+        window['globalThis'] = window;
+    }
+
+    /******************************************************************************
+    Copyright (c) Microsoft Corporation.
+
+    Permission to use, copy, modify, and/or distribute this software for any
+    purpose with or without fee is hereby granted.
+
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+    PERFORMANCE OF THIS SOFTWARE.
+    ***************************************************************************** */
+    /* global Reflect, Promise */
+
+    var extendStatics = function(d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+
+    function __extends(d, b) {
+        if (typeof b !== "function" && b !== null)
+            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    }
+
+    var __assign = function() {
+        __assign = Object.assign || function __assign(t) {
+            for (var s, i = 1, n = arguments.length; i < n; i++) {
+                s = arguments[i];
+                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
+            }
+            return t;
+        };
+        return __assign.apply(this, arguments);
+    };
+
+    function __awaiter(thisArg, _arguments, P, generator) {
+        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+        return new (P || (P = Promise))(function (resolve, reject) {
+            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+            step((generator = generator.apply(thisArg, _arguments || [])).next());
+        });
+    }
+
+    function __generator(thisArg, body) {
+        var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
+        return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
+        function verb(n) { return function (v) { return step([n, v]); }; }
+        function step(op) {
+            if (f) throw new TypeError("Generator is already executing.");
+            while (g && (g = 0, op[0] && (_ = 0)), _) try {
+                if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
+                if (y = 0, t) op = [op[0] & 2, t.value];
+                switch (op[0]) {
+                    case 0: case 1: t = op; break;
+                    case 4: _.label++; return { value: op[1], done: false };
+                    case 5: _.label++; y = op[1]; op = [0]; continue;
+                    case 7: op = _.ops.pop(); _.trys.pop(); continue;
+                    default:
+                        if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
+                        if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
+                        if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
+                        if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
+                        if (t[2]) _.ops.pop();
+                        _.trys.pop(); continue;
+                }
+                op = body.call(thisArg, _);
+            } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
+            if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
+        }
+    }
+
+    function __classPrivateFieldGet(receiver, state, kind, f) {
+        if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+        if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+        return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+    }
+
+    function __classPrivateFieldSet(receiver, state, value, kind, f) {
+        if (kind === "m") throw new TypeError("Private method is not writable");
+        if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+        if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+        return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+    }
+
+    var CloseCode;
+    (function (CloseCode) {
+        CloseCode[CloseCode["CONSENTED"] = 4000] = "CONSENTED";
+        CloseCode[CloseCode["DEVMODE_RESTART"] = 4010] = "DEVMODE_RESTART";
+    })(CloseCode || (CloseCode = {}));
+    var ServerError = /** @class */ (function (_super) {
+        __extends(ServerError, _super);
+        function ServerError(code, message) {
+            var _this = _super.call(this, message) || this;
+            _this.name = "ServerError";
+            _this.code = code;
+            return _this;
+        }
+        return ServerError;
+    }(Error));
+
+    /**
+     * Copyright (c) 2014 Ion Drive Software Ltd.
+     * https://github.com/darrachequesne/notepack/
+     *
+     * Permission is hereby granted, free of charge, to any person obtaining a copy
+     * of this software and associated documentation files (the "Software"), to deal
+     * in the Software without restriction, including without limitation the rights
+     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+     * copies of the Software, and to permit persons to whom the Software is
+     * furnished to do so, subject to the following conditions:
+     *
+     * The above copyright notice and this permission notice shall be included in all
+     * copies or substantial portions of the Software.
+     *
+     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+     * SOFTWARE.
+     */
+    /**
+     * Patch for Colyseus:
+     * -------------------
+     * notepack.io@3.0.1
+     *
+     * added `offset` on Decoder constructor, for messages arriving with a code
+     * before actual msgpack data
+     */
+    //
+    // DECODER
+    //
+    function Decoder(buffer, offset) {
+        this._offset = offset;
+        if (buffer instanceof ArrayBuffer) {
+            this._buffer = buffer;
+            this._view = new DataView(this._buffer);
+        }
+        else if (ArrayBuffer.isView(buffer)) {
+            this._buffer = buffer.buffer;
+            this._view = new DataView(this._buffer, buffer.byteOffset, buffer.byteLength);
+        }
+        else {
+            throw new Error('Invalid argument');
+        }
+    }
+    function utf8Read$1(view, offset, length) {
+        var string = '', chr = 0;
+        for (var i = offset, end = offset + length; i < end; i++) {
+            var byte = view.getUint8(i);
+            if ((byte & 0x80) === 0x00) {
+                string += String.fromCharCode(byte);
+                continue;
+            }
+            if ((byte & 0xe0) === 0xc0) {
+                string += String.fromCharCode(((byte & 0x1f) << 6) |
+                    (view.getUint8(++i) & 0x3f));
+                continue;
+            }
+            if ((byte & 0xf0) === 0xe0) {
+                string += String.fromCharCode(((byte & 0x0f) << 12) |
+                    ((view.getUint8(++i) & 0x3f) << 6) |
+                    ((view.getUint8(++i) & 0x3f) << 0));
+                continue;
+            }
+            if ((byte & 0xf8) === 0xf0) {
+                chr = ((byte & 0x07) << 18) |
+                    ((view.getUint8(++i) & 0x3f) << 12) |
+                    ((view.getUint8(++i) & 0x3f) << 6) |
+                    ((view.getUint8(++i) & 0x3f) << 0);
+                if (chr >= 0x010000) { // surrogate pair
+                    chr -= 0x010000;
+                    string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00);
+                }
+                else {
+                    string += String.fromCharCode(chr);
+                }
+                continue;
+            }
+            throw new Error('Invalid byte ' + byte.toString(16));
+        }
+        return string;
+    }
+    Decoder.prototype._array = function (length) {
+        var value = new Array(length);
+        for (var i = 0; i < length; i++) {
+            value[i] = this._parse();
+        }
+        return value;
+    };
+    Decoder.prototype._map = function (length) {
+        var key = '', value = {};
+        for (var i = 0; i < length; i++) {
+            key = this._parse();
+            value[key] = this._parse();
+        }
+        return value;
+    };
+    Decoder.prototype._str = function (length) {
+        var value = utf8Read$1(this._view, this._offset, length);
+        this._offset += length;
+        return value;
+    };
+    Decoder.prototype._bin = function (length) {
+        var value = this._buffer.slice(this._offset, this._offset + length);
+        this._offset += length;
+        return value;
+    };
+    Decoder.prototype._parse = function () {
+        var prefix = this._view.getUint8(this._offset++);
+        var value, length = 0, type = 0, hi = 0, lo = 0;
+        if (prefix < 0xc0) {
+            // positive fixint
+            if (prefix < 0x80) {
+                return prefix;
+            }
+            // fixmap
+            if (prefix < 0x90) {
+                return this._map(prefix & 0x0f);
+            }
+            // fixarray
+            if (prefix < 0xa0) {
+                return this._array(prefix & 0x0f);
+            }
+            // fixstr
+            return this._str(prefix & 0x1f);
+        }
+        // negative fixint
+        if (prefix > 0xdf) {
+            return (0xff - prefix + 1) * -1;
+        }
+        switch (prefix) {
+            // nil
+            case 0xc0:
+                return null;
+            // false
+            case 0xc2:
+                return false;
+            // true
+            case 0xc3:
+                return true;
+            // bin
+            case 0xc4:
+                length = this._view.getUint8(this._offset);
+                this._offset += 1;
+                return this._bin(length);
+            case 0xc5:
+                length = this._view.getUint16(this._offset);
+                this._offset += 2;
+                return this._bin(length);
+            case 0xc6:
+                length = this._view.getUint32(this._offset);
+                this._offset += 4;
+                return this._bin(length);
+            // ext
+            case 0xc7:
+                length = this._view.getUint8(this._offset);
+                type = this._view.getInt8(this._offset + 1);
+                this._offset += 2;
+                if (type === -1) {
+                    // timestamp 96
+                    var ns = this._view.getUint32(this._offset);
+                    hi = this._view.getInt32(this._offset + 4);
+                    lo = this._view.getUint32(this._offset + 8);
+                    this._offset += 12;
+                    return new Date((hi * 0x100000000 + lo) * 1e3 + ns / 1e6);
+                }
+                return [type, this._bin(length)];
+            case 0xc8:
+                length = this._view.getUint16(this._offset);
+                type = this._view.getInt8(this._offset + 2);
+                this._offset += 3;
+                return [type, this._bin(length)];
+            case 0xc9:
+                length = this._view.getUint32(this._offset);
+                type = this._view.getInt8(this._offset + 4);
+                this._offset += 5;
+                return [type, this._bin(length)];
+            // float
+            case 0xca:
+                value = this._view.getFloat32(this._offset);
+                this._offset += 4;
+                return value;
+            case 0xcb:
+                value = this._view.getFloat64(this._offset);
+                this._offset += 8;
+                return value;
+            // uint
+            case 0xcc:
+                value = this._view.getUint8(this._offset);
+                this._offset += 1;
+                return value;
+            case 0xcd:
+                value = this._view.getUint16(this._offset);
+                this._offset += 2;
+                return value;
+            case 0xce:
+                value = this._view.getUint32(this._offset);
+                this._offset += 4;
+                return value;
+            case 0xcf:
+                hi = this._view.getUint32(this._offset) * Math.pow(2, 32);
+                lo = this._view.getUint32(this._offset + 4);
+                this._offset += 8;
+                return hi + lo;
+            // int
+            case 0xd0:
+                value = this._view.getInt8(this._offset);
+                this._offset += 1;
+                return value;
+            case 0xd1:
+                value = this._view.getInt16(this._offset);
+                this._offset += 2;
+                return value;
+            case 0xd2:
+                value = this._view.getInt32(this._offset);
+                this._offset += 4;
+                return value;
+            case 0xd3:
+                hi = this._view.getInt32(this._offset) * Math.pow(2, 32);
+                lo = this._view.getUint32(this._offset + 4);
+                this._offset += 8;
+                return hi + lo;
+            // fixext
+            case 0xd4:
+                type = this._view.getInt8(this._offset);
+                this._offset += 1;
+                if (type === 0x00) {
+                    // custom encoding for 'undefined' (kept for backward-compatibility)
+                    this._offset += 1;
+                    return void 0;
+                }
+                return [type, this._bin(1)];
+            case 0xd5:
+                type = this._view.getInt8(this._offset);
+                this._offset += 1;
+                return [type, this._bin(2)];
+            case 0xd6:
+                type = this._view.getInt8(this._offset);
+                this._offset += 1;
+                if (type === -1) {
+                    // timestamp 32
+                    value = this._view.getUint32(this._offset);
+                    this._offset += 4;
+                    return new Date(value * 1e3);
+                }
+                return [type, this._bin(4)];
+            case 0xd7:
+                type = this._view.getInt8(this._offset);
+                this._offset += 1;
+                if (type === 0x00) {
+                    // custom date encoding (kept for backward-compatibility)
+                    hi = this._view.getInt32(this._offset) * Math.pow(2, 32);
+                    lo = this._view.getUint32(this._offset + 4);
+                    this._offset += 8;
+                    return new Date(hi + lo);
+                }
+                if (type === -1) {
+                    // timestamp 64
+                    hi = this._view.getUint32(this._offset);
+                    lo = this._view.getUint32(this._offset + 4);
+                    this._offset += 8;
+                    var s = (hi & 0x3) * 0x100000000 + lo;
+                    return new Date(s * 1e3 + (hi >>> 2) / 1e6);
+                }
+                return [type, this._bin(8)];
+            case 0xd8:
+                type = this._view.getInt8(this._offset);
+                this._offset += 1;
+                return [type, this._bin(16)];
+            // str
+            case 0xd9:
+                length = this._view.getUint8(this._offset);
+                this._offset += 1;
+                return this._str(length);
+            case 0xda:
+                length = this._view.getUint16(this._offset);
+                this._offset += 2;
+                return this._str(length);
+            case 0xdb:
+                length = this._view.getUint32(this._offset);
+                this._offset += 4;
+                return this._str(length);
+            // array
+            case 0xdc:
+                length = this._view.getUint16(this._offset);
+                this._offset += 2;
+                return this._array(length);
+            case 0xdd:
+                length = this._view.getUint32(this._offset);
+                this._offset += 4;
+                return this._array(length);
+            // map
+            case 0xde:
+                length = this._view.getUint16(this._offset);
+                this._offset += 2;
+                return this._map(length);
+            case 0xdf:
+                length = this._view.getUint32(this._offset);
+                this._offset += 4;
+                return this._map(length);
+        }
+        throw new Error('Could not parse');
+    };
+    function decode(buffer, offset) {
+        if (offset === void 0) { offset = 0; }
+        var decoder = new Decoder(buffer, offset);
+        var value = decoder._parse();
+        if (decoder._offset !== buffer.byteLength) {
+            throw new Error((buffer.byteLength - decoder._offset) + ' trailing bytes');
+        }
+        return value;
+    }
+    //
+    // ENCODER
+    //
+    var TIMESTAMP32_MAX_SEC = 0x100000000 - 1; // 32-bit unsigned int
+    var TIMESTAMP64_MAX_SEC = 0x400000000 - 1; // 34-bit unsigned int
+    function utf8Write(view, offset, str) {
+        var c = 0;
+        for (var i = 0, l = str.length; i < l; i++) {
+            c = str.charCodeAt(i);
+            if (c < 0x80) {
+                view.setUint8(offset++, c);
+            }
+            else if (c < 0x800) {
+                view.setUint8(offset++, 0xc0 | (c >> 6));
+                view.setUint8(offset++, 0x80 | (c & 0x3f));
+            }
+            else if (c < 0xd800 || c >= 0xe000) {
+                view.setUint8(offset++, 0xe0 | (c >> 12));
+                view.setUint8(offset++, 0x80 | (c >> 6) & 0x3f);
+                view.setUint8(offset++, 0x80 | (c & 0x3f));
+            }
+            else {
+                i++;
+                c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
+                view.setUint8(offset++, 0xf0 | (c >> 18));
+                view.setUint8(offset++, 0x80 | (c >> 12) & 0x3f);
+                view.setUint8(offset++, 0x80 | (c >> 6) & 0x3f);
+                view.setUint8(offset++, 0x80 | (c & 0x3f));
+            }
+        }
+    }
+    function utf8Length$1(str) {
+        var c = 0, length = 0;
+        for (var i = 0, l = str.length; i < l; i++) {
+            c = str.charCodeAt(i);
+            if (c < 0x80) {
+                length += 1;
+            }
+            else if (c < 0x800) {
+                length += 2;
+            }
+            else if (c < 0xd800 || c >= 0xe000) {
+                length += 3;
+            }
+            else {
+                i++;
+                length += 4;
+            }
+        }
+        return length;
+    }
+    function _encode(bytes, defers, value) {
+        var type = typeof value, i = 0, l = 0, hi = 0, lo = 0, length = 0, size = 0;
+        if (type === 'string') {
+            length = utf8Length$1(value);
+            // fixstr
+            if (length < 0x20) {
+                bytes.push(length | 0xa0);
+                size = 1;
+            }
+            // str 8
+            else if (length < 0x100) {
+                bytes.push(0xd9, length);
+                size = 2;
+            }
+            // str 16
+            else if (length < 0x10000) {
+                bytes.push(0xda, length >> 8, length);
+                size = 3;
+            }
+            // str 32
+            else if (length < 0x100000000) {
+                bytes.push(0xdb, length >> 24, length >> 16, length >> 8, length);
+                size = 5;
+            }
+            else {
+                throw new Error('String too long');
+            }
+            defers.push({ _str: value, _length: length, _offset: bytes.length });
+            return size + length;
+        }
+        if (type === 'number') {
+            // TODO: encode to float 32?
+            // float 64
+            if (Math.floor(value) !== value || !isFinite(value)) {
+                bytes.push(0xcb);
+                defers.push({ _float: value, _length: 8, _offset: bytes.length });
+                return 9;
+            }
+            if (value >= 0) {
+                // positive fixnum
+                if (value < 0x80) {
+                    bytes.push(value);
+                    return 1;
+                }
+                // uint 8
+                if (value < 0x100) {
+                    bytes.push(0xcc, value);
+                    return 2;
+                }
+                // uint 16
+                if (value < 0x10000) {
+                    bytes.push(0xcd, value >> 8, value);
+                    return 3;
+                }
+                // uint 32
+                if (value < 0x100000000) {
+                    bytes.push(0xce, value >> 24, value >> 16, value >> 8, value);
+                    return 5;
+                }
+                // uint 64
+                hi = (value / Math.pow(2, 32)) >> 0;
+                lo = value >>> 0;
+                bytes.push(0xcf, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo);
+                return 9;
+            }
+            else {
+                // negative fixnum
+                if (value >= -0x20) {
+                    bytes.push(value);
+                    return 1;
+                }
+                // int 8
+                if (value >= -0x80) {
+                    bytes.push(0xd0, value);
+                    return 2;
+                }
+                // int 16
+                if (value >= -0x8000) {
+                    bytes.push(0xd1, value >> 8, value);
+                    return 3;
+                }
+                // int 32
+                if (value >= -0x80000000) {
+                    bytes.push(0xd2, value >> 24, value >> 16, value >> 8, value);
+                    return 5;
+                }
+                // int 64
+                hi = Math.floor(value / Math.pow(2, 32));
+                lo = value >>> 0;
+                bytes.push(0xd3, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo);
+                return 9;
+            }
+        }
+        if (type === 'object') {
+            // nil
+            if (value === null) {
+                bytes.push(0xc0);
+                return 1;
+            }
+            if (Array.isArray(value)) {
+                length = value.length;
+                // fixarray
+                if (length < 0x10) {
+                    bytes.push(length | 0x90);
+                    size = 1;
+                }
+                // array 16
+                else if (length < 0x10000) {
+                    bytes.push(0xdc, length >> 8, length);
+                    size = 3;
+                }
+                // array 32
+                else if (length < 0x100000000) {
+                    bytes.push(0xdd, length >> 24, length >> 16, length >> 8, length);
+                    size = 5;
+                }
+                else {
+                    throw new Error('Array too large');
+                }
+                for (i = 0; i < length; i++) {
+                    size += _encode(bytes, defers, value[i]);
+                }
+                return size;
+            }
+            if (value instanceof Date) {
+                var ms = value.getTime();
+                var s = Math.floor(ms / 1e3);
+                var ns = (ms - s * 1e3) * 1e6;
+                if (s >= 0 && ns >= 0 && s <= TIMESTAMP64_MAX_SEC) {
+                    if (ns === 0 && s <= TIMESTAMP32_MAX_SEC) {
+                        // timestamp 32
+                        bytes.push(0xd6, 0xff, s >> 24, s >> 16, s >> 8, s);
+                        return 6;
+                    }
+                    else {
+                        // timestamp 64
+                        hi = s / 0x100000000;
+                        lo = s & 0xffffffff;
+                        bytes.push(0xd7, 0xff, ns >> 22, ns >> 14, ns >> 6, hi, lo >> 24, lo >> 16, lo >> 8, lo);
+                        return 10;
+                    }
+                }
+                else {
+                    // timestamp 96
+                    hi = Math.floor(s / 0x100000000);
+                    lo = s >>> 0;
+                    bytes.push(0xc7, 0x0c, 0xff, ns >> 24, ns >> 16, ns >> 8, ns, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo);
+                    return 15;
+                }
+            }
+            if (value instanceof ArrayBuffer) {
+                length = value.byteLength;
+                // bin 8
+                if (length < 0x100) {
+                    bytes.push(0xc4, length);
+                    size = 2;
+                }
+                else 
+                // bin 16
+                if (length < 0x10000) {
+                    bytes.push(0xc5, length >> 8, length);
+                    size = 3;
+                }
+                else 
+                // bin 32
+                if (length < 0x100000000) {
+                    bytes.push(0xc6, length >> 24, length >> 16, length >> 8, length);
+                    size = 5;
+                }
+                else {
+                    throw new Error('Buffer too large');
+                }
+                defers.push({ _bin: value, _length: length, _offset: bytes.length });
+                return size + length;
+            }
+            if (typeof value.toJSON === 'function') {
+                return _encode(bytes, defers, value.toJSON());
+            }
+            var keys = [], key = '';
+            var allKeys = Object.keys(value);
+            for (i = 0, l = allKeys.length; i < l; i++) {
+                key = allKeys[i];
+                if (value[key] !== undefined && typeof value[key] !== 'function') {
+                    keys.push(key);
+                }
+            }
+            length = keys.length;
+            // fixmap
+            if (length < 0x10) {
+                bytes.push(length | 0x80);
+                size = 1;
+            }
+            // map 16
+            else if (length < 0x10000) {
+                bytes.push(0xde, length >> 8, length);
+                size = 3;
+            }
+            // map 32
+            else if (length < 0x100000000) {
+                bytes.push(0xdf, length >> 24, length >> 16, length >> 8, length);
+                size = 5;
+            }
+            else {
+                throw new Error('Object too large');
+            }
+            for (i = 0; i < length; i++) {
+                key = keys[i];
+                size += _encode(bytes, defers, key);
+                size += _encode(bytes, defers, value[key]);
+            }
+            return size;
+        }
+        // false/true
+        if (type === 'boolean') {
+            bytes.push(value ? 0xc3 : 0xc2);
+            return 1;
+        }
+        if (type === 'undefined') {
+            bytes.push(0xc0);
+            return 1;
+        }
+        // custom types like BigInt (typeof value === 'bigint')
+        if (typeof value.toJSON === 'function') {
+            return _encode(bytes, defers, value.toJSON());
+        }
+        throw new Error('Could not encode');
+    }
+    function encode(value) {
+        var bytes = [];
+        var defers = [];
+        var size = _encode(bytes, defers, value);
+        var buf = new ArrayBuffer(size);
+        var view = new DataView(buf);
+        var deferIndex = 0;
+        var deferWritten = 0;
+        var nextOffset = -1;
+        if (defers.length > 0) {
+            nextOffset = defers[0]._offset;
+        }
+        var defer, deferLength = 0, offset = 0;
+        for (var i = 0, l = bytes.length; i < l; i++) {
+            view.setUint8(deferWritten + i, bytes[i]);
+            if (i + 1 !== nextOffset) {
+                continue;
+            }
+            defer = defers[deferIndex];
+            deferLength = defer._length;
+            offset = deferWritten + nextOffset;
+            if (defer._bin) {
+                var bin = new Uint8Array(defer._bin);
+                for (var j = 0; j < deferLength; j++) {
+                    view.setUint8(offset + j, bin[j]);
+                }
+            }
+            else if (defer._str) {
+                utf8Write(view, offset, defer._str);
+            }
+            else if (defer._float !== undefined) {
+                view.setFloat64(offset, defer._float);
+            }
+            deferIndex++;
+            deferWritten += deferLength;
+            if (defers[deferIndex]) {
+                nextOffset = defers[deferIndex]._offset;
+            }
+        }
+        return buf;
+    }
+
+    var browser = function () {
+      throw new Error(
+        'ws does not work in the browser. Browser clients must use the native ' +
+          'WebSocket object'
+      );
+    };
+
+    var WebSocket = globalThis.WebSocket || browser;
+    var WebSocketTransport = /** @class */ (function () {
+        function WebSocketTransport(events) {
+            this.events = events;
+        }
+        WebSocketTransport.prototype.send = function (data) {
+            if (data instanceof ArrayBuffer) {
+                this.ws.send(data);
+            }
+            else if (Array.isArray(data)) {
+                this.ws.send((new Uint8Array(data)).buffer);
+            }
+        };
+        WebSocketTransport.prototype.connect = function (url) {
+            this.ws = new WebSocket(url, this.protocols);
+            this.ws.binaryType = 'arraybuffer';
+            this.ws.onopen = this.events.onopen || function () {};
+            this.ws.onmessage = this.events.onmessage || function () {};
+            this.ws.onclose = this.events.onclose || function () {};
+            this.ws.onerror = this.events.onerror || function () {};
+        };
+        WebSocketTransport.prototype.close = function (code, reason) {
+            this.ws.close(code, reason);
+        };
+        Object.defineProperty(WebSocketTransport.prototype, "isOpen", {
+            get: function () {
+                return this.ws.readyState === WebSocket.OPEN;
+            },
+            enumerable: false,
+            configurable: true
+        });
+        return WebSocketTransport;
+    }());
+
+    var Connection = /** @class */ (function () {
+        function Connection() {
+            this.events = {};
+            this.transport = new WebSocketTransport(this.events);
+        }
+        Connection.prototype.send = function (data) {
+            this.transport.send(data);
+        };
+        Connection.prototype.connect = function (url) {
+            this.transport.connect(url);
+        };
+        Connection.prototype.close = function (code, reason) {
+            this.transport.close(code, reason);
+        };
+        Object.defineProperty(Connection.prototype, "isOpen", {
+            get: function () {
+                return this.transport.isOpen;
+            },
+            enumerable: false,
+            configurable: true
+        });
+        return Connection;
+    }());
+
+    // Use codes between 0~127 for lesser throughput (1 byte)
+    exports.Protocol = void 0;
+    (function (Protocol) {
+        // Room-related (10~19)
+        Protocol[Protocol["HANDSHAKE"] = 9] = "HANDSHAKE";
+        Protocol[Protocol["JOIN_ROOM"] = 10] = "JOIN_ROOM";
+        Protocol[Protocol["ERROR"] = 11] = "ERROR";
+        Protocol[Protocol["LEAVE_ROOM"] = 12] = "LEAVE_ROOM";
+        Protocol[Protocol["ROOM_DATA"] = 13] = "ROOM_DATA";
+        Protocol[Protocol["ROOM_STATE"] = 14] = "ROOM_STATE";
+        Protocol[Protocol["ROOM_STATE_PATCH"] = 15] = "ROOM_STATE_PATCH";
+        Protocol[Protocol["ROOM_DATA_SCHEMA"] = 16] = "ROOM_DATA_SCHEMA";
+        Protocol[Protocol["ROOM_DATA_BYTES"] = 17] = "ROOM_DATA_BYTES";
+    })(exports.Protocol || (exports.Protocol = {}));
+    exports.ErrorCode = void 0;
+    (function (ErrorCode) {
+        ErrorCode[ErrorCode["MATCHMAKE_NO_HANDLER"] = 4210] = "MATCHMAKE_NO_HANDLER";
+        ErrorCode[ErrorCode["MATCHMAKE_INVALID_CRITERIA"] = 4211] = "MATCHMAKE_INVALID_CRITERIA";
+        ErrorCode[ErrorCode["MATCHMAKE_INVALID_ROOM_ID"] = 4212] = "MATCHMAKE_INVALID_ROOM_ID";
+        ErrorCode[ErrorCode["MATCHMAKE_UNHANDLED"] = 4213] = "MATCHMAKE_UNHANDLED";
+        ErrorCode[ErrorCode["MATCHMAKE_EXPIRED"] = 4214] = "MATCHMAKE_EXPIRED";
+        ErrorCode[ErrorCode["AUTH_FAILED"] = 4215] = "AUTH_FAILED";
+        ErrorCode[ErrorCode["APPLICATION_ERROR"] = 4216] = "APPLICATION_ERROR";
+    })(exports.ErrorCode || (exports.ErrorCode = {}));
+    function utf8Read(view, offset) {
+        var length = view[offset++];
+        var string = '', chr = 0;
+        for (var i = offset, end = offset + length; i < end; i++) {
+            var byte = view[i];
+            if ((byte & 0x80) === 0x00) {
+                string += String.fromCharCode(byte);
+                continue;
+            }
+            if ((byte & 0xe0) === 0xc0) {
+                string += String.fromCharCode(((byte & 0x1f) << 6) |
+                    (view[++i] & 0x3f));
+                continue;
+            }
+            if ((byte & 0xf0) === 0xe0) {
+                string += String.fromCharCode(((byte & 0x0f) << 12) |
+                    ((view[++i] & 0x3f) << 6) |
+                    ((view[++i] & 0x3f) << 0));
+                continue;
+            }
+            if ((byte & 0xf8) === 0xf0) {
+                chr = ((byte & 0x07) << 18) |
+                    ((view[++i] & 0x3f) << 12) |
+                    ((view[++i] & 0x3f) << 6) |
+                    ((view[++i] & 0x3f) << 0);
+                if (chr >= 0x010000) { // surrogate pair
+                    chr -= 0x010000;
+                    string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00);
+                }
+                else {
+                    string += String.fromCharCode(chr);
+                }
+                continue;
+            }
+            throw new Error('Invalid byte ' + byte.toString(16));
+        }
+        return string;
+    }
+    // Faster for short strings than Buffer.byteLength
+    function utf8Length(str) {
+        if (str === void 0) { str = ''; }
+        var c = 0;
+        var length = 0;
+        for (var i = 0, l = str.length; i < l; i++) {
+            c = str.charCodeAt(i);
+            if (c < 0x80) {
+                length += 1;
+            }
+            else if (c < 0x800) {
+                length += 2;
+            }
+            else if (c < 0xd800 || c >= 0xe000) {
+                length += 3;
+            }
+            else {
+                i++;
+                length += 4;
+            }
+        }
+        return length + 1;
+    }
+
+    var serializers = {};
+    function registerSerializer(id, serializer) {
+        serializers[id] = serializer;
+    }
+    function getSerializer(id) {
+        var serializer = serializers[id];
+        if (!serializer) {
+            throw new Error("missing serializer: " + id);
+        }
+        return serializer;
+    }
+
+    /**
+     * The MIT License (MIT)
+     *
+     * Copyright 2016 Andrey Sitnik <andrey@sitnik.ru>
+     *
+     * Permission is hereby granted, free of charge, to any person obtaining a copy of
+     * this software and associated documentation files (the "Software"), to deal in
+     * the Software without restriction, including without limitation the rights to
+     * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+     * the Software, and to permit persons to whom the Software is furnished to do so,
+     * subject to the following conditions:
+     *
+     * The above copyright notice and this permission notice shall be included in all
+     * copies or substantial portions of the Software.
+     *
+     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+     * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+     * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+     * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+     * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+     */
+    var createNanoEvents = function () { return ({
+        emit: function (event) {
+            var args = [];
+            for (var _i = 1; _i < arguments.length; _i++) {
+                args[_i - 1] = arguments[_i];
+            }
+            var callbacks = this.events[event] || [];
+            for (var i = 0, length_1 = callbacks.length; i < length_1; i++) {
+                callbacks[i].apply(callbacks, args);
+            }
+        },
+        events: {},
+        on: function (event, cb) {
+            var _this = this;
+            var _a;
+            ((_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.push(cb)) || (this.events[event] = [cb]);
+            return function () {
+                var _a;
+                _this.events[event] = (_a = _this.events[event]) === null || _a === void 0 ? void 0 : _a.filter(function (i) { return cb !== i; });
+            };
+        }
+    }); };
+
+    var EventEmitter = /** @class */ (function () {
+        function EventEmitter() {
+            this.handlers = [];
+        }
+        EventEmitter.prototype.register = function (cb, once) {
+            this.handlers.push(cb);
+            return this;
+        };
+        EventEmitter.prototype.invoke = function () {
+            var _this = this;
+            var args = [];
+            for (var _i = 0; _i < arguments.length; _i++) {
+                args[_i] = arguments[_i];
+            }
+            this.handlers.forEach(function (handler) { return handler.apply(_this, args); });
+        };
+        EventEmitter.prototype.invokeAsync = function () {
+            var _this = this;
+            var args = [];
+            for (var _i = 0; _i < arguments.length; _i++) {
+                args[_i] = arguments[_i];
+            }
+            return Promise.all(this.handlers.map(function (handler) { return handler.apply(_this, args); }));
+        };
+        EventEmitter.prototype.remove = function (cb) {
+            var index = this.handlers.indexOf(cb);
+            this.handlers[index] = this.handlers[this.handlers.length - 1];
+            this.handlers.pop();
+        };
+        EventEmitter.prototype.clear = function () {
+            this.handlers = [];
+        };
+        return EventEmitter;
+    }());
+    function createSignal() {
+        var emitter = new EventEmitter();
+        function register(cb) {
+            return emitter.register(cb, this === null);
+        }
+        register.once = function (cb) {
+            var callback = function () {
+                var args = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    args[_i] = arguments[_i];
+                }
+                cb.apply(this, args);
+                emitter.remove(callback);
+            };
+            emitter.register(callback);
+        };
+        register.remove = function (cb) { return emitter.remove(cb); };
+        register.invoke = function () {
+            var args = [];
+            for (var _i = 0; _i < arguments.length; _i++) {
+                args[_i] = arguments[_i];
+            }
+            return emitter.invoke.apply(emitter, args);
+        };
+        register.invokeAsync = function () {
+            var args = [];
+            for (var _i = 0; _i < arguments.length; _i++) {
+                args[_i] = arguments[_i];
+            }
+            return emitter.invokeAsync.apply(emitter, args);
+        };
+        register.clear = function () { return emitter.clear(); };
+        return register;
+    }
+
+    var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+    function createCommonjsModule(fn) {
+      var module = { exports: {} };
+    	return fn(module, module.exports), module.exports;
+    }
+
+    var umd = createCommonjsModule(function (module, exports) {
+    (function (global, factory) {
+        factory(exports) ;
+    })(commonjsGlobal, (function (exports) {
+        /******************************************************************************
+        Copyright (c) Microsoft Corporation.
+
+        Permission to use, copy, modify, and/or distribute this software for any
+        purpose with or without fee is hereby granted.
+
+        THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+        REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+        AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+        INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+        LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+        OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+        PERFORMANCE OF THIS SOFTWARE.
+        ***************************************************************************** */
+        /* global Reflect, Promise */
+
+        var extendStatics = function(d, b) {
+            extendStatics = Object.setPrototypeOf ||
+                ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+                function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
+            return extendStatics(d, b);
+        };
+
+        function __extends(d, b) {
+            if (typeof b !== "function" && b !== null)
+                throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
+            extendStatics(d, b);
+            function __() { this.constructor = d; }
+            d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+        }
+
+        function __decorate(decorators, target, key, desc) {
+            var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+            if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+            else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+            return c > 3 && r && Object.defineProperty(target, key, r), r;
+        }
+
+        function __spreadArray(to, from, pack) {
+            if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
+                if (ar || !(i in from)) {
+                    if (!ar) ar = Array.prototype.slice.call(from, 0, i);
+                    ar[i] = from[i];
+                }
+            }
+            return to.concat(ar || Array.prototype.slice.call(from));
+        }
+
+        // export const SWITCH_TO_STRUCTURE = 193; (easily collides with DELETE_AND_ADD + fieldIndex = 2)
+        var SWITCH_TO_STRUCTURE = 255; // (decoding collides with DELETE_AND_ADD + fieldIndex = 63)
+        var TYPE_ID = 213;
+        /**
+         * Encoding Schema field operations.
+         */
+        exports.OPERATION = void 0;
+        (function (OPERATION) {
+            // add new structure/primitive
+            OPERATION[OPERATION["ADD"] = 128] = "ADD";
+            // replace structure/primitive
+            OPERATION[OPERATION["REPLACE"] = 0] = "REPLACE";
+            // delete field
+            OPERATION[OPERATION["DELETE"] = 64] = "DELETE";
+            // DELETE field, followed by an ADD
+            OPERATION[OPERATION["DELETE_AND_ADD"] = 192] = "DELETE_AND_ADD";
+            // TOUCH is used to determine hierarchy of nested Schema structures during serialization.
+            // touches are NOT encoded.
+            OPERATION[OPERATION["TOUCH"] = 1] = "TOUCH";
+            // MapSchema Operations
+            OPERATION[OPERATION["CLEAR"] = 10] = "CLEAR";
+        })(exports.OPERATION || (exports.OPERATION = {}));
+        // export enum OPERATION {
+        //     // add new structure/primitive
+        //     // (128)
+        //     ADD = 128, // 10000000,
+        //     // replace structure/primitive
+        //     REPLACE = 1,// 00000001
+        //     // delete field
+        //     DELETE = 192, // 11000000
+        //     // DELETE field, followed by an ADD
+        //     DELETE_AND_ADD = 224, // 11100000
+        //     // TOUCH is used to determine hierarchy of nested Schema structures during serialization.
+        //     // touches are NOT encoded.
+        //     TOUCH = 0, // 00000000
+        //     // MapSchema Operations
+        //     CLEAR = 10,
+        // }
+
+        var ChangeTree = /** @class */ (function () {
+            function ChangeTree(ref, parent, root) {
+                this.changed = false;
+                this.changes = new Map();
+                this.allChanges = new Set();
+                // cached indexes for filtering
+                this.caches = {};
+                this.currentCustomOperation = 0;
+                this.ref = ref;
+                this.setParent(parent, root);
+            }
+            ChangeTree.prototype.setParent = function (parent, root, parentIndex) {
+                var _this = this;
+                if (!this.indexes) {
+                    this.indexes = (this.ref instanceof Schema)
+                        ? this.ref['_definition'].indexes
+                        : {};
+                }
+                this.parent = parent;
+                this.parentIndex = parentIndex;
+                // avoid setting parents with empty `root`
+                if (!root) {
+                    return;
+                }
+                this.root = root;
+                //
+                // assign same parent on child structures
+                //
+                if (this.ref instanceof Schema) {
+                    var definition = this.ref['_definition'];
+                    for (var field in definition.schema) {
+                        var value = this.ref[field];
+                        if (value && value['$changes']) {
+                            var parentIndex_1 = definition.indexes[field];
+                            value['$changes'].setParent(this.ref, root, parentIndex_1);
+                        }
+                    }
+                }
+                else if (typeof (this.ref) === "object") {
+                    this.ref.forEach(function (value, key) {
+                        if (value instanceof Schema) {
+                            var changeTreee = value['$changes'];
+                            var parentIndex_2 = _this.ref['$changes'].indexes[key];
+                            changeTreee.setParent(_this.ref, _this.root, parentIndex_2);
+                        }
+                    });
+                }
+            };
+            ChangeTree.prototype.operation = function (op) {
+                this.changes.set(--this.currentCustomOperation, op);
+            };
+            ChangeTree.prototype.change = function (fieldName, operation) {
+                if (operation === void 0) { operation = exports.OPERATION.ADD; }
+                var index = (typeof (fieldName) === "number")
+                    ? fieldName
+                    : this.indexes[fieldName];
+                this.assertValidIndex(index, fieldName);
+                var previousChange = this.changes.get(index);
+                if (!previousChange ||
+                    previousChange.op === exports.OPERATION.DELETE ||
+                    previousChange.op === exports.OPERATION.TOUCH // (mazmorra.io's BattleAction issue)
+                ) {
+                    this.changes.set(index, {
+                        op: (!previousChange)
+                            ? operation
+                            : (previousChange.op === exports.OPERATION.DELETE)
+                                ? exports.OPERATION.DELETE_AND_ADD
+                                : operation,
+                        // : OPERATION.REPLACE,
+                        index: index
+                    });
+                }
+                this.allChanges.add(index);
+                this.changed = true;
+                this.touchParents();
+            };
+            ChangeTree.prototype.touch = function (fieldName) {
+                var index = (typeof (fieldName) === "number")
+                    ? fieldName
+                    : this.indexes[fieldName];
+                this.assertValidIndex(index, fieldName);
+                if (!this.changes.has(index)) {
+                    this.changes.set(index, { op: exports.OPERATION.TOUCH, index: index });
+                }
+                this.allChanges.add(index);
+                // ensure touch is placed until the $root is found.
+                this.touchParents();
+            };
+            ChangeTree.prototype.touchParents = function () {
+                if (this.parent) {
+                    this.parent['$changes'].touch(this.parentIndex);
+                }
+            };
+            ChangeTree.prototype.getType = function (index) {
+                if (this.ref['_definition']) {
+                    var definition = this.ref['_definition'];
+                    return definition.schema[definition.fieldsByIndex[index]];
+                }
+                else {
+                    var definition = this.parent['_definition'];
+                    var parentType = definition.schema[definition.fieldsByIndex[this.parentIndex]];
+                    //
+                    // Get the child type from parent structure.
+                    // - ["string"] => "string"
+                    // - { map: "string" } => "string"
+                    // - { set: "string" } => "string"
+                    //
+                    return Object.values(parentType)[0];
+                }
+            };
+            ChangeTree.prototype.getChildrenFilter = function () {
+                var childFilters = this.parent['_definition'].childFilters;
+                return childFilters && childFilters[this.parentIndex];
+            };
+            //
+            // used during `.encode()`
+            //
+            ChangeTree.prototype.getValue = function (index) {
+                return this.ref['getByIndex'](index);
+            };
+            ChangeTree.prototype.delete = function (fieldName) {
+                var index = (typeof (fieldName) === "number")
+                    ? fieldName
+                    : this.indexes[fieldName];
+                if (index === undefined) {
+                    console.warn("@colyseus/schema ".concat(this.ref.constructor.name, ": trying to delete non-existing index: ").concat(fieldName, " (").concat(index, ")"));
+                    return;
+                }
+                var previousValue = this.getValue(index);
+                // console.log("$changes.delete =>", { fieldName, index, previousValue });
+                this.changes.set(index, { op: exports.OPERATION.DELETE, index: index });
+                this.allChanges.delete(index);
+                // delete cache
+                delete this.caches[index];
+                // remove `root` reference
+                if (previousValue && previousValue['$changes']) {
+                    previousValue['$changes'].parent = undefined;
+                }
+                this.changed = true;
+                this.touchParents();
+            };
+            ChangeTree.prototype.discard = function (changed, discardAll) {
+                var _this = this;
+                if (changed === void 0) { changed = false; }
+                if (discardAll === void 0) { discardAll = false; }
+                //
+                // Map, Array, etc:
+                // Remove cached key to ensure ADD operations is unsed instead of
+                // REPLACE in case same key is used on next patches.
+                //
+                // TODO: refactor this. this is not relevant for Collection and Set.
+                //
+                if (!(this.ref instanceof Schema)) {
+                    this.changes.forEach(function (change) {
+                        if (change.op === exports.OPERATION.DELETE) {
+                            var index = _this.ref['getIndex'](change.index);
+                            delete _this.indexes[index];
+                        }
+                    });
+                }
+                this.changes.clear();
+                this.changed = changed;
+                if (discardAll) {
+                    this.allChanges.clear();
+                }
+                // re-set `currentCustomOperation`
+                this.currentCustomOperation = 0;
+            };
+            /**
+             * Recursively discard all changes from this, and child structures.
+             */
+            ChangeTree.prototype.discardAll = function () {
+                var _this = this;
+                this.changes.forEach(function (change) {
+                    var value = _this.getValue(change.index);
+                    if (value && value['$changes']) {
+                        value['$changes'].discardAll();
+                    }
+                });
+                this.discard();
+            };
+            // cache(field: number, beginIndex: number, endIndex: number) {
+            ChangeTree.prototype.cache = function (field, cachedBytes) {
+                this.caches[field] = cachedBytes;
+            };
+            ChangeTree.prototype.clone = function () {
+                return new ChangeTree(this.ref, this.parent, this.root);
+            };
+            ChangeTree.prototype.ensureRefId = function () {
+                // skip if refId is already set.
+                if (this.refId !== undefined) {
+                    return;
+                }
+                this.refId = this.root.getNextUniqueId();
+            };
+            ChangeTree.prototype.assertValidIndex = function (index, fieldName) {
+                if (index === undefined) {
+                    throw new Error("ChangeTree: missing index for field \"".concat(fieldName, "\""));
+                }
+            };
+            return ChangeTree;
+        }());
+
+        function addCallback($callbacks, op, callback, existing) {
+            // initialize list of callbacks
+            if (!$callbacks[op]) {
+                $callbacks[op] = [];
+            }
+            $callbacks[op].push(callback);
+            //
+            // Trigger callback for existing elements
+            // - OPERATION.ADD
+            // - OPERATION.REPLACE
+            //
+            existing === null || existing === void 0 ? void 0 : existing.forEach(function (item, key) { return callback(item, key); });
+            return function () { return spliceOne($callbacks[op], $callbacks[op].indexOf(callback)); };
+        }
+        function removeChildRefs(changes) {
+            var _this = this;
+            var needRemoveRef = (typeof (this.$changes.getType()) !== "string");
+            this.$items.forEach(function (item, key) {
+                changes.push({
+                    refId: _this.$changes.refId,
+                    op: exports.OPERATION.DELETE,
+                    field: key,
+                    value: undefined,
+                    previousValue: item
+                });
+                if (needRemoveRef) {
+                    _this.$changes.root.removeRef(item['$changes'].refId);
+                }
+            });
+        }
+        function spliceOne(arr, index) {
+            // manually splice an array
+            if (index === -1 || index >= arr.length) {
+                return false;
+            }
+            var len = arr.length - 1;
+            for (var i = index; i < len; i++) {
+                arr[i] = arr[i + 1];
+            }
+            arr.length = len;
+            return true;
+        }
+
+        var DEFAULT_SORT = function (a, b) {
+            var A = a.toString();
+            var B = b.toString();
+            if (A < B)
+                return -1;
+            else if (A > B)
+                return 1;
+            else
+                return 0;
+        };
+        function getArrayProxy(value) {
+            value['$proxy'] = true;
+            //
+            // compatibility with @colyseus/schema 0.5.x
+            // - allow `map["key"]`
+            // - allow `map["key"] = "xxx"`
+            // - allow `delete map["key"]`
+            //
+            value = new Proxy(value, {
+                get: function (obj, prop) {
+                    if (typeof (prop) !== "symbol" &&
+                        !isNaN(prop) // https://stackoverflow.com/a/175787/892698
+                    ) {
+                        return obj.at(prop);
+                    }
+                    else {
+                        return obj[prop];
+                    }
+                },
+                set: function (obj, prop, setValue) {
+                    if (typeof (prop) !== "symbol" &&
+                        !isNaN(prop)) {
+                        var indexes = Array.from(obj['$items'].keys());
+                        var key = parseInt(indexes[prop] || prop);
+                        if (setValue === undefined || setValue === null) {
+                            obj.deleteAt(key);
+                        }
+                        else {
+                            obj.setAt(key, setValue);
+                        }
+                    }
+                    else {
+                        obj[prop] = setValue;
+                    }
+                    return true;
+                },
+                deleteProperty: function (obj, prop) {
+                    if (typeof (prop) === "number") {
+                        obj.deleteAt(prop);
+                    }
+                    else {
+                        delete obj[prop];
+                    }
+                    return true;
+                },
+            });
+            return value;
+        }
+        var ArraySchema = /** @class */ (function () {
+            function ArraySchema() {
+                var items = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    items[_i] = arguments[_i];
+                }
+                this.$changes = new ChangeTree(this);
+                this.$items = new Map();
+                this.$indexes = new Map();
+                this.$refId = 0;
+                this.push.apply(this, items);
+            }
+            ArraySchema.prototype.onAdd = function (callback, triggerAll) {
+                if (triggerAll === void 0) { triggerAll = true; }
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.ADD, callback, (triggerAll)
+                    ? this.$items
+                    : undefined);
+            };
+            ArraySchema.prototype.onRemove = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.DELETE, callback); };
+            ArraySchema.prototype.onChange = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.REPLACE, callback); };
+            ArraySchema.is = function (type) {
+                return (
+                // type format: ["string"]
+                Array.isArray(type) ||
+                    // type format: { array: "string" }
+                    (type['array'] !== undefined));
+            };
+            Object.defineProperty(ArraySchema.prototype, "length", {
+                get: function () {
+                    return this.$items.size;
+                },
+                set: function (value) {
+                    if (value === 0) {
+                        this.clear();
+                    }
+                    else {
+                        this.splice(value, this.length - value);
+                    }
+                },
+                enumerable: false,
+                configurable: true
+            });
+            ArraySchema.prototype.push = function () {
+                var _this = this;
+                var values = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    values[_i] = arguments[_i];
+                }
+                var lastIndex;
+                values.forEach(function (value) {
+                    // set "index" for reference.
+                    lastIndex = _this.$refId++;
+                    _this.setAt(lastIndex, value);
+                });
+                return lastIndex;
+            };
+            /**
+             * Removes the last element from an array and returns it.
+             */
+            ArraySchema.prototype.pop = function () {
+                var key = Array.from(this.$indexes.values()).pop();
+                if (key === undefined) {
+                    return undefined;
+                }
+                this.$changes.delete(key);
+                this.$indexes.delete(key);
+                var value = this.$items.get(key);
+                this.$items.delete(key);
+                return value;
+            };
+            ArraySchema.prototype.at = function (index) {
+                //
+                // FIXME: this should be O(1)
+                //
+                var key = Array.from(this.$items.keys())[index];
+                return this.$items.get(key);
+            };
+            ArraySchema.prototype.setAt = function (index, value) {
+                var _a, _b;
+                if (value['$changes'] !== undefined) {
+                    value['$changes'].setParent(this, this.$changes.root, index);
+                }
+                var operation = (_b = (_a = this.$changes.indexes[index]) === null || _a === void 0 ? void 0 : _a.op) !== null && _b !== void 0 ? _b : exports.OPERATION.ADD;
+                this.$changes.indexes[index] = index;
+                this.$indexes.set(index, index);
+                this.$items.set(index, value);
+                this.$changes.change(index, operation);
+            };
+            ArraySchema.prototype.deleteAt = function (index) {
+                var key = Array.from(this.$items.keys())[index];
+                if (key === undefined) {
+                    return false;
+                }
+                return this.$deleteAt(key);
+            };
+            ArraySchema.prototype.$deleteAt = function (index) {
+                // delete at internal index
+                this.$changes.delete(index);
+                this.$indexes.delete(index);
+                return this.$items.delete(index);
+            };
+            ArraySchema.prototype.clear = function (changes) {
+                // discard previous operations.
+                this.$changes.discard(true, true);
+                this.$changes.indexes = {};
+                // clear previous indexes
+                this.$indexes.clear();
+                //
+                // When decoding:
+                // - enqueue items for DELETE callback.
+                // - flag child items for garbage collection.
+                //
+                if (changes) {
+                    removeChildRefs.call(this, changes);
+                }
+                // clear items
+                this.$items.clear();
+                this.$changes.operation({ index: 0, op: exports.OPERATION.CLEAR });
+                // touch all structures until reach root
+                this.$changes.touchParents();
+            };
+            /**
+             * Combines two or more arrays.
+             * @param items Additional items to add to the end of array1.
+             */
+            // @ts-ignore
+            ArraySchema.prototype.concat = function () {
+                var _a;
+                var items = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    items[_i] = arguments[_i];
+                }
+                return new (ArraySchema.bind.apply(ArraySchema, __spreadArray([void 0], (_a = Array.from(this.$items.values())).concat.apply(_a, items), false)))();
+            };
+            /**
+             * Adds all the elements of an array separated by the specified separator string.
+             * @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
+             */
+            ArraySchema.prototype.join = function (separator) {
+                return Array.from(this.$items.values()).join(separator);
+            };
+            /**
+             * Reverses the elements in an Array.
+             */
+            // @ts-ignore
+            ArraySchema.prototype.reverse = function () {
+                var _this = this;
+                var indexes = Array.from(this.$items.keys());
+                var reversedItems = Array.from(this.$items.values()).reverse();
+                reversedItems.forEach(function (item, i) {
+                    _this.setAt(indexes[i], item);
+                });
+                return this;
+            };
+            /**
+             * Removes the first element from an array and returns it.
+             */
+            ArraySchema.prototype.shift = function () {
+                var indexes = Array.from(this.$items.keys());
+                var shiftAt = indexes.shift();
+                if (shiftAt === undefined) {
+                    return undefined;
+                }
+                var value = this.$items.get(shiftAt);
+                this.$deleteAt(shiftAt);
+                return value;
+            };
+            /**
+             * Returns a section of an array.
+             * @param start The beginning of the specified portion of the array.
+             * @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.
+             */
+            ArraySchema.prototype.slice = function (start, end) {
+                var sliced = new ArraySchema();
+                sliced.push.apply(sliced, Array.from(this.$items.values()).slice(start, end));
+                return sliced;
+            };
+            /**
+             * Sorts an array.
+             * @param compareFn Function used to determine the order of the elements. It is expected to return
+             * a negative value if first argument is less than second argument, zero if they're equal and a positive
+             * value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.
+             * ```ts
+             * [11,2,22,1].sort((a, b) => a - b)
+             * ```
+             */
+            ArraySchema.prototype.sort = function (compareFn) {
+                var _this = this;
+                if (compareFn === void 0) { compareFn = DEFAULT_SORT; }
+                var indexes = Array.from(this.$items.keys());
+                var sortedItems = Array.from(this.$items.values()).sort(compareFn);
+                sortedItems.forEach(function (item, i) {
+                    _this.setAt(indexes[i], item);
+                });
+                return this;
+            };
+            /**
+             * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
+             * @param start The zero-based location in the array from which to start removing elements.
+             * @param deleteCount The number of elements to remove.
+             * @param items Elements to insert into the array in place of the deleted elements.
+             */
+            ArraySchema.prototype.splice = function (start, deleteCount) {
+                if (deleteCount === void 0) { deleteCount = this.length - start; }
+                var indexes = Array.from(this.$items.keys());
+                var removedItems = [];
+                for (var i = start; i < start + deleteCount; i++) {
+                    removedItems.push(this.$items.get(indexes[i]));
+                    this.$deleteAt(indexes[i]);
+                }
+                return removedItems;
+            };
+            /**
+             * Inserts new elements at the start of an array.
+             * @param items  Elements to insert at the start of the Array.
+             */
+            ArraySchema.prototype.unshift = function () {
+                var _this = this;
+                var items = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    items[_i] = arguments[_i];
+                }
+                var length = this.length;
+                var addedLength = items.length;
+                // const indexes = Array.from(this.$items.keys());
+                var previousValues = Array.from(this.$items.values());
+                items.forEach(function (item, i) {
+                    _this.setAt(i, item);
+                });
+                previousValues.forEach(function (previousValue, i) {
+                    _this.setAt(addedLength + i, previousValue);
+                });
+                return length + addedLength;
+            };
+            /**
+             * Returns the index of the first occurrence of a value in an array.
+             * @param searchElement The value to locate in the array.
+             * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
+             */
+            ArraySchema.prototype.indexOf = function (searchElement, fromIndex) {
+                return Array.from(this.$items.values()).indexOf(searchElement, fromIndex);
+            };
+            /**
+             * Returns the index of the last occurrence of a specified value in an array.
+             * @param searchElement The value to locate in the array.
+             * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at the last index in the array.
+             */
+            ArraySchema.prototype.lastIndexOf = function (searchElement, fromIndex) {
+                if (fromIndex === void 0) { fromIndex = this.length - 1; }
+                return Array.from(this.$items.values()).lastIndexOf(searchElement, fromIndex);
+            };
+            /**
+             * Determines whether all the members of an array satisfy the specified test.
+             * @param callbackfn A function that accepts up to three arguments. The every method calls
+             * the callbackfn function for each element in the array until the callbackfn returns a value
+             * which is coercible to the Boolean value false, or until the end of the array.
+             * @param thisArg An object to which the this keyword can refer in the callbackfn function.
+             * If thisArg is omitted, undefined is used as the this value.
+             */
+            ArraySchema.prototype.every = function (callbackfn, thisArg) {
+                return Array.from(this.$items.values()).every(callbackfn, thisArg);
+            };
+            /**
+             * Determines whether the specified callback function returns true for any element of an array.
+             * @param callbackfn A function that accepts up to three arguments. The some method calls
+             * the callbackfn function for each element in the array until the callbackfn returns a value
+             * which is coercible to the Boolean value true, or until the end of the array.
+             * @param thisArg An object to which the this keyword can refer in the callbackfn function.
+             * If thisArg is omitted, undefined is used as the this value.
+             */
+            ArraySchema.prototype.some = function (callbackfn, thisArg) {
+                return Array.from(this.$items.values()).some(callbackfn, thisArg);
+            };
+            /**
+             * Performs the specified action for each element in an array.
+             * @param callbackfn  A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.
+             * @param thisArg  An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
+             */
+            ArraySchema.prototype.forEach = function (callbackfn, thisArg) {
+                Array.from(this.$items.values()).forEach(callbackfn, thisArg);
+            };
+            /**
+             * Calls a defined callback function on each element of an array, and returns an array that contains the results.
+             * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
+             * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
+             */
+            ArraySchema.prototype.map = function (callbackfn, thisArg) {
+                return Array.from(this.$items.values()).map(callbackfn, thisArg);
+            };
+            ArraySchema.prototype.filter = function (callbackfn, thisArg) {
+                return Array.from(this.$items.values()).filter(callbackfn, thisArg);
+            };
+            /**
+             * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
+             * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
+             * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
+             */
+            ArraySchema.prototype.reduce = function (callbackfn, initialValue) {
+                return Array.prototype.reduce.apply(Array.from(this.$items.values()), arguments);
+            };
+            /**
+             * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
+             * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array.
+             * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
+             */
+            ArraySchema.prototype.reduceRight = function (callbackfn, initialValue) {
+                return Array.prototype.reduceRight.apply(Array.from(this.$items.values()), arguments);
+            };
+            /**
+             * Returns the value of the first element in the array where predicate is true, and undefined
+             * otherwise.
+             * @param predicate find calls predicate once for each element of the array, in ascending
+             * order, until it finds one where predicate returns true. If such an element is found, find
+             * immediately returns that element value. Otherwise, find returns undefined.
+             * @param thisArg If provided, it will be used as the this value for each invocation of
+             * predicate. If it is not provided, undefined is used instead.
+             */
+            ArraySchema.prototype.find = function (predicate, thisArg) {
+                return Array.from(this.$items.values()).find(predicate, thisArg);
+            };
+            /**
+             * Returns the index of the first element in the array where predicate is true, and -1
+             * otherwise.
+             * @param predicate find calls predicate once for each element of the array, in ascending
+             * order, until it finds one where predicate returns true. If such an element is found,
+             * findIndex immediately returns that element index. Otherwise, findIndex returns -1.
+             * @param thisArg If provided, it will be used as the this value for each invocation of
+             * predicate. If it is not provided, undefined is used instead.
+             */
+            ArraySchema.prototype.findIndex = function (predicate, thisArg) {
+                return Array.from(this.$items.values()).findIndex(predicate, thisArg);
+            };
+            /**
+             * Returns the this object after filling the section identified by start and end with value
+             * @param value value to fill array section with
+             * @param start index to start filling the array at. If start is negative, it is treated as
+             * length+start where length is the length of the array.
+             * @param end index to stop filling the array at. If end is negative, it is treated as
+             * length+end.
+             */
+            ArraySchema.prototype.fill = function (value, start, end) {
+                //
+                // TODO
+                //
+                throw new Error("ArraySchema#fill() not implemented");
+            };
+            /**
+             * Returns the this object after copying a section of the array identified by start and end
+             * to the same array starting at position target
+             * @param target If target is negative, it is treated as length+target where length is the
+             * length of the array.
+             * @param start If start is negative, it is treated as length+start. If end is negative, it
+             * is treated as length+end.
+             * @param end If not specified, length of the this object is used as its default value.
+             */
+            ArraySchema.prototype.copyWithin = function (target, start, end) {
+                //
+                // TODO
+                //
+                throw new Error("ArraySchema#copyWithin() not implemented");
+            };
+            /**
+             * Returns a string representation of an array.
+             */
+            ArraySchema.prototype.toString = function () { return this.$items.toString(); };
+            /**
+             * Returns a string representation of an array. The elements are converted to string using their toLocalString methods.
+             */
+            ArraySchema.prototype.toLocaleString = function () { return this.$items.toLocaleString(); };
+            /** Iterator */
+            ArraySchema.prototype[Symbol.iterator] = function () {
+                return Array.from(this.$items.values())[Symbol.iterator]();
+            };
+            /**
+             * Returns an iterable of key, value pairs for every entry in the array
+             */
+            ArraySchema.prototype.entries = function () { return this.$items.entries(); };
+            /**
+             * Returns an iterable of keys in the array
+             */
+            ArraySchema.prototype.keys = function () { return this.$items.keys(); };
+            /**
+             * Returns an iterable of values in the array
+             */
+            ArraySchema.prototype.values = function () { return this.$items.values(); };
+            /**
+             * Determines whether an array includes a certain element, returning true or false as appropriate.
+             * @param searchElement The element to search for.
+             * @param fromIndex The position in this array at which to begin searching for searchElement.
+             */
+            ArraySchema.prototype.includes = function (searchElement, fromIndex) {
+                return Array.from(this.$items.values()).includes(searchElement, fromIndex);
+            };
+            /**
+             * Calls a defined callback function on each element of an array. Then, flattens the result into
+             * a new array.
+             * This is identical to a map followed by flat with depth 1.
+             *
+             * @param callback A function that accepts up to three arguments. The flatMap method calls the
+             * callback function one time for each element in the array.
+             * @param thisArg An object to which the this keyword can refer in the callback function. If
+             * thisArg is omitted, undefined is used as the this value.
+             */
+            // @ts-ignore
+            ArraySchema.prototype.flatMap = function (callback, thisArg) {
+                // @ts-ignore
+                throw new Error("ArraySchema#flatMap() is not supported.");
+            };
+            /**
+             * Returns a new array with all sub-array elements concatenated into it recursively up to the
+             * specified depth.
+             *
+             * @param depth The maximum recursion depth
+             */
+            // @ts-ignore
+            ArraySchema.prototype.flat = function (depth) {
+                throw new Error("ArraySchema#flat() is not supported.");
+            };
+            ArraySchema.prototype.findLast = function () {
+                var arr = Array.from(this.$items.values());
+                // @ts-ignore
+                return arr.findLast.apply(arr, arguments);
+            };
+            ArraySchema.prototype.findLastIndex = function () {
+                var arr = Array.from(this.$items.values());
+                // @ts-ignore
+                return arr.findLastIndex.apply(arr, arguments);
+            };
+            // get size () {
+            //     return this.$items.size;
+            // }
+            ArraySchema.prototype.setIndex = function (index, key) {
+                this.$indexes.set(index, key);
+            };
+            ArraySchema.prototype.getIndex = function (index) {
+                return this.$indexes.get(index);
+            };
+            ArraySchema.prototype.getByIndex = function (index) {
+                return this.$items.get(this.$indexes.get(index));
+            };
+            ArraySchema.prototype.deleteByIndex = function (index) {
+                var key = this.$indexes.get(index);
+                this.$items.delete(key);
+                this.$indexes.delete(index);
+            };
+            ArraySchema.prototype.toArray = function () {
+                return Array.from(this.$items.values());
+            };
+            ArraySchema.prototype.toJSON = function () {
+                return this.toArray().map(function (value) {
+                    return (typeof (value['toJSON']) === "function")
+                        ? value['toJSON']()
+                        : value;
+                });
+            };
+            //
+            // Decoding utilities
+            //
+            ArraySchema.prototype.clone = function (isDecoding) {
+                var cloned;
+                if (isDecoding) {
+                    cloned = new (ArraySchema.bind.apply(ArraySchema, __spreadArray([void 0], Array.from(this.$items.values()), false)))();
+                }
+                else {
+                    cloned = new (ArraySchema.bind.apply(ArraySchema, __spreadArray([void 0], this.map(function (item) { return ((item['$changes'])
+                        ? item.clone()
+                        : item); }), false)))();
+                }
+                return cloned;
+            };
+            return ArraySchema;
+        }());
+
+        function getMapProxy(value) {
+            value['$proxy'] = true;
+            value = new Proxy(value, {
+                get: function (obj, prop) {
+                    if (typeof (prop) !== "symbol" && // accessing properties
+                        typeof (obj[prop]) === "undefined") {
+                        return obj.get(prop);
+                    }
+                    else {
+                        return obj[prop];
+                    }
+                },
+                set: function (obj, prop, setValue) {
+                    if (typeof (prop) !== "symbol" &&
+                        (prop.indexOf("$") === -1 &&
+                            prop !== "onAdd" &&
+                            prop !== "onRemove" &&
+                            prop !== "onChange")) {
+                        obj.set(prop, setValue);
+                    }
+                    else {
+                        obj[prop] = setValue;
+                    }
+                    return true;
+                },
+                deleteProperty: function (obj, prop) {
+                    obj.delete(prop);
+                    return true;
+                },
+            });
+            return value;
+        }
+        var MapSchema = /** @class */ (function () {
+            function MapSchema(initialValues) {
+                var _this = this;
+                this.$changes = new ChangeTree(this);
+                this.$items = new Map();
+                this.$indexes = new Map();
+                this.$refId = 0;
+                if (initialValues) {
+                    if (initialValues instanceof Map ||
+                        initialValues instanceof MapSchema) {
+                        initialValues.forEach(function (v, k) { return _this.set(k, v); });
+                    }
+                    else {
+                        for (var k in initialValues) {
+                            this.set(k, initialValues[k]);
+                        }
+                    }
+                }
+            }
+            MapSchema.prototype.onAdd = function (callback, triggerAll) {
+                if (triggerAll === void 0) { triggerAll = true; }
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.ADD, callback, (triggerAll)
+                    ? this.$items
+                    : undefined);
+            };
+            MapSchema.prototype.onRemove = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.DELETE, callback); };
+            MapSchema.prototype.onChange = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.REPLACE, callback); };
+            MapSchema.is = function (type) {
+                return type['map'] !== undefined;
+            };
+            /** Iterator */
+            MapSchema.prototype[Symbol.iterator] = function () { return this.$items[Symbol.iterator](); };
+            Object.defineProperty(MapSchema.prototype, Symbol.toStringTag, {
+                get: function () { return this.$items[Symbol.toStringTag]; },
+                enumerable: false,
+                configurable: true
+            });
+            MapSchema.prototype.set = function (key, value) {
+                if (value === undefined || value === null) {
+                    throw new Error("MapSchema#set('".concat(key, "', ").concat(value, "): trying to set ").concat(value, " value on '").concat(key, "'."));
+                }
+                // get "index" for this value.
+                var hasIndex = typeof (this.$changes.indexes[key]) !== "undefined";
+                var index = (hasIndex)
+                    ? this.$changes.indexes[key]
+                    : this.$refId++;
+                var operation = (hasIndex)
+                    ? exports.OPERATION.REPLACE
+                    : exports.OPERATION.ADD;
+                var isRef = (value['$changes']) !== undefined;
+                if (isRef) {
+                    value['$changes'].setParent(this, this.$changes.root, index);
+                }
+                //
+                // (encoding)
+                // set a unique id to relate directly with this key/value.
+                //
+                if (!hasIndex) {
+                    this.$changes.indexes[key] = index;
+                    this.$indexes.set(index, key);
+                }
+                else if (isRef && // if is schema, force ADD operation if value differ from previous one.
+                    this.$items.get(key) !== value) {
+                    operation = exports.OPERATION.ADD;
+                }
+                this.$items.set(key, value);
+                this.$changes.change(key, operation);
+                return this;
+            };
+            MapSchema.prototype.get = function (key) {
+                return this.$items.get(key);
+            };
+            MapSchema.prototype.delete = function (key) {
+                //
+                // TODO: add a "purge" method after .encode() runs, to cleanup removed `$indexes`
+                //
+                // We don't remove $indexes to allow setting the same key in the same patch
+                // (See "should allow to remove and set an item in the same place" test)
+                //
+                // // const index = this.$changes.indexes[key];
+                // // this.$indexes.delete(index);
+                this.$changes.delete(key);
+                return this.$items.delete(key);
+            };
+            MapSchema.prototype.clear = function (changes) {
+                // discard previous operations.
+                this.$changes.discard(true, true);
+                this.$changes.indexes = {};
+                // clear previous indexes
+                this.$indexes.clear();
+                //
+                // When decoding:
+                // - enqueue items for DELETE callback.
+                // - flag child items for garbage collection.
+                //
+                if (changes) {
+                    removeChildRefs.call(this, changes);
+                }
+                // clear items
+                this.$items.clear();
+                this.$changes.operation({ index: 0, op: exports.OPERATION.CLEAR });
+                // touch all structures until reach root
+                this.$changes.touchParents();
+            };
+            MapSchema.prototype.has = function (key) {
+                return this.$items.has(key);
+            };
+            MapSchema.prototype.forEach = function (callbackfn) {
+                this.$items.forEach(callbackfn);
+            };
+            MapSchema.prototype.entries = function () {
+                return this.$items.entries();
+            };
+            MapSchema.prototype.keys = function () {
+                return this.$items.keys();
+            };
+            MapSchema.prototype.values = function () {
+                return this.$items.values();
+            };
+            Object.defineProperty(MapSchema.prototype, "size", {
+                get: function () {
+                    return this.$items.size;
+                },
+                enumerable: false,
+                configurable: true
+            });
+            MapSchema.prototype.setIndex = function (index, key) {
+                this.$indexes.set(index, key);
+            };
+            MapSchema.prototype.getIndex = function (index) {
+                return this.$indexes.get(index);
+            };
+            MapSchema.prototype.getByIndex = function (index) {
+                return this.$items.get(this.$indexes.get(index));
+            };
+            MapSchema.prototype.deleteByIndex = function (index) {
+                var key = this.$indexes.get(index);
+                this.$items.delete(key);
+                this.$indexes.delete(index);
+            };
+            MapSchema.prototype.toJSON = function () {
+                var map = {};
+                this.forEach(function (value, key) {
+                    map[key] = (typeof (value['toJSON']) === "function")
+                        ? value['toJSON']()
+                        : value;
+                });
+                return map;
+            };
+            //
+            // Decoding utilities
+            //
+            MapSchema.prototype.clone = function (isDecoding) {
+                var cloned;
+                if (isDecoding) {
+                    // client-side
+                    cloned = Object.assign(new MapSchema(), this);
+                }
+                else {
+                    // server-side
+                    cloned = new MapSchema();
+                    this.forEach(function (value, key) {
+                        if (value['$changes']) {
+                            cloned.set(key, value['clone']());
+                        }
+                        else {
+                            cloned.set(key, value);
+                        }
+                    });
+                }
+                return cloned;
+            };
+            return MapSchema;
+        }());
+
+        var registeredTypes = {};
+        function registerType(identifier, definition) {
+            registeredTypes[identifier] = definition;
+        }
+        function getType(identifier) {
+            return registeredTypes[identifier];
+        }
+
+        var SchemaDefinition = /** @class */ (function () {
+            function SchemaDefinition() {
+                //
+                // TODO: use a "field" structure combining all these properties per-field.
+                //
+                this.indexes = {};
+                this.fieldsByIndex = {};
+                this.deprecated = {};
+                this.descriptors = {};
+            }
+            SchemaDefinition.create = function (parent) {
+                var definition = new SchemaDefinition();
+                // support inheritance
+                definition.schema = Object.assign({}, parent && parent.schema || {});
+                definition.indexes = Object.assign({}, parent && parent.indexes || {});
+                definition.fieldsByIndex = Object.assign({}, parent && parent.fieldsByIndex || {});
+                definition.descriptors = Object.assign({}, parent && parent.descriptors || {});
+                definition.deprecated = Object.assign({}, parent && parent.deprecated || {});
+                return definition;
+            };
+            SchemaDefinition.prototype.addField = function (field, type) {
+                var index = this.getNextFieldIndex();
+                this.fieldsByIndex[index] = field;
+                this.indexes[field] = index;
+                this.schema[field] = (Array.isArray(type))
+                    ? { array: type[0] }
+                    : type;
+            };
+            SchemaDefinition.prototype.hasField = function (field) {
+                return this.indexes[field] !== undefined;
+            };
+            SchemaDefinition.prototype.addFilter = function (field, cb) {
+                if (!this.filters) {
+                    this.filters = {};
+                    this.indexesWithFilters = [];
+                }
+                this.filters[this.indexes[field]] = cb;
+                this.indexesWithFilters.push(this.indexes[field]);
+                return true;
+            };
+            SchemaDefinition.prototype.addChildrenFilter = function (field, cb) {
+                var index = this.indexes[field];
+                var type = this.schema[field];
+                if (getType(Object.keys(type)[0])) {
+                    if (!this.childFilters) {
+                        this.childFilters = {};
+                    }
+                    this.childFilters[index] = cb;
+                    return true;
+                }
+                else {
+                    console.warn("@filterChildren: field '".concat(field, "' can't have children. Ignoring filter."));
+                }
+            };
+            SchemaDefinition.prototype.getChildrenFilter = function (field) {
+                return this.childFilters && this.childFilters[this.indexes[field]];
+            };
+            SchemaDefinition.prototype.getNextFieldIndex = function () {
+                return Object.keys(this.schema || {}).length;
+            };
+            return SchemaDefinition;
+        }());
+        function hasFilter(klass) {
+            return klass._context && klass._context.useFilters;
+        }
+        var Context = /** @class */ (function () {
+            function Context() {
+                this.types = {};
+                this.schemas = new Map();
+                this.useFilters = false;
+            }
+            Context.prototype.has = function (schema) {
+                return this.schemas.has(schema);
+            };
+            Context.prototype.get = function (typeid) {
+                return this.types[typeid];
+            };
+            Context.prototype.add = function (schema, typeid) {
+                if (typeid === void 0) { typeid = this.schemas.size; }
+                // FIXME: move this to somewhere else?
+                // support inheritance
+                schema._definition = SchemaDefinition.create(schema._definition);
+                schema._typeid = typeid;
+                this.types[typeid] = schema;
+                this.schemas.set(schema, typeid);
+            };
+            Context.create = function (options) {
+                if (options === void 0) { options = {}; }
+                return function (definition) {
+                    if (!options.context) {
+                        options.context = new Context();
+                    }
+                    return type(definition, options);
+                };
+            };
+            return Context;
+        }());
+        var globalContext = new Context();
+        /**
+         * [See documentation](https://docs.colyseus.io/state/schema/)
+         *
+         * Annotate a Schema property to be serializeable.
+         * \@type()'d fields are automatically flagged as "dirty" for the next patch.
+         *
+         * @example Standard usage, with automatic change tracking.
+         * ```
+         * \@type("string") propertyName: string;
+         * ```
+         *
+         * @example You can provide the "manual" option if you'd like to manually control your patches via .setDirty().
+         * ```
+         * \@type("string", { manual: true })
+         * ```
+         */
+        function type(type, options) {
+            if (options === void 0) { options = {}; }
+            return function (target, field) {
+                var context = options.context || globalContext;
+                var constructor = target.constructor;
+                constructor._context = context;
+                if (!type) {
+                    throw new Error("".concat(constructor.name, ": @type() reference provided for \"").concat(field, "\" is undefined. Make sure you don't have any circular dependencies."));
+                }
+                /*
+                 * static schema
+                 */
+                if (!context.has(constructor)) {
+                    context.add(constructor);
+                }
+                var definition = constructor._definition;
+                definition.addField(field, type);
+                /**
+                 * skip if descriptor already exists for this field (`@deprecated()`)
+                 */
+                if (definition.descriptors[field]) {
+                    if (definition.deprecated[field]) {
+                        // do not create accessors for deprecated properties.
+                        return;
+                    }
+                    else {
+                        // trying to define same property multiple times across inheritance.
+                        // https://github.com/colyseus/colyseus-unity3d/issues/131#issuecomment-814308572
+                        try {
+                            throw new Error("@colyseus/schema: Duplicate '".concat(field, "' definition on '").concat(constructor.name, "'.\nCheck @type() annotation"));
+                        }
+                        catch (e) {
+                            var definitionAtLine = e.stack.split("\n")[4].trim();
+                            throw new Error("".concat(e.message, " ").concat(definitionAtLine));
+                        }
+                    }
+                }
+                var isArray = ArraySchema.is(type);
+                var isMap = !isArray && MapSchema.is(type);
+                // TODO: refactor me.
+                // Allow abstract intermediary classes with no fields to be serialized
+                // (See "should support an inheritance with a Schema type without fields" test)
+                if (typeof (type) !== "string" && !Schema.is(type)) {
+                    var childType = Object.values(type)[0];
+                    if (typeof (childType) !== "string" && !context.has(childType)) {
+                        context.add(childType);
+                    }
+                }
+                if (options.manual) {
+                    // do not declare getter/setter descriptor
+                    definition.descriptors[field] = {
+                        enumerable: true,
+                        configurable: true,
+                        writable: true,
+                    };
+                    return;
+                }
+                var fieldCached = "_".concat(field);
+                definition.descriptors[fieldCached] = {
+                    enumerable: false,
+                    configurable: false,
+                    writable: true,
+                };
+                definition.descriptors[field] = {
+                    get: function () {
+                        return this[fieldCached];
+                    },
+                    set: function (value) {
+                        /**
+                         * Create Proxy for array or map items
+                         */
+                        // skip if value is the same as cached.
+                        if (value === this[fieldCached]) {
+                            return;
+                        }
+                        if (value !== undefined &&
+                            value !== null) {
+                            // automaticallty transform Array into ArraySchema
+                            if (isArray && !(value instanceof ArraySchema)) {
+                                value = new (ArraySchema.bind.apply(ArraySchema, __spreadArray([void 0], value, false)))();
+                            }
+                            // automaticallty transform Map into MapSchema
+                            if (isMap && !(value instanceof MapSchema)) {
+                                value = new MapSchema(value);
+                            }
+                            // try to turn provided structure into a Proxy
+                            if (value['$proxy'] === undefined) {
+                                if (isMap) {
+                                    value = getMapProxy(value);
+                                }
+                                else if (isArray) {
+                                    value = getArrayProxy(value);
+                                }
+                            }
+                            // flag the change for encoding.
+                            this.$changes.change(field);
+                            //
+                            // call setParent() recursively for this and its child
+                            // structures.
+                            //
+                            if (value['$changes']) {
+                                value['$changes'].setParent(this, this.$changes.root, this._definition.indexes[field]);
+                            }
+                        }
+                        else if (this[fieldCached]) {
+                            //
+                            // Setting a field to `null` or `undefined` will delete it.
+                            //
+                            this.$changes.delete(field);
+                        }
+                        this[fieldCached] = value;
+                    },
+                    enumerable: true,
+                    configurable: true
+                };
+            };
+        }
+        /**
+         * `@filter()` decorator for defining data filters per client
+         */
+        function filter(cb) {
+            return function (target, field) {
+                var constructor = target.constructor;
+                var definition = constructor._definition;
+                if (definition.addFilter(field, cb)) {
+                    constructor._context.useFilters = true;
+                }
+            };
+        }
+        function filterChildren(cb) {
+            return function (target, field) {
+                var constructor = target.constructor;
+                var definition = constructor._definition;
+                if (definition.addChildrenFilter(field, cb)) {
+                    constructor._context.useFilters = true;
+                }
+            };
+        }
+        /**
+         * `@deprecated()` flag a field as deprecated.
+         * The previous `@type()` annotation should remain along with this one.
+         */
+        function deprecated(throws) {
+            if (throws === void 0) { throws = true; }
+            return function (target, field) {
+                var constructor = target.constructor;
+                var definition = constructor._definition;
+                definition.deprecated[field] = true;
+                if (throws) {
+                    definition.descriptors[field] = {
+                        get: function () { throw new Error("".concat(field, " is deprecated.")); },
+                        set: function (value) { },
+                        enumerable: false,
+                        configurable: true
+                    };
+                }
+            };
+        }
+        function defineTypes(target, fields, options) {
+            if (options === void 0) { options = {}; }
+            if (!options.context) {
+                options.context = target._context || options.context || globalContext;
+            }
+            for (var field in fields) {
+                type(fields[field], options)(target.prototype, field);
+            }
+            return target;
+        }
+
+        /**
+         * Copyright (c) 2018 Endel Dreyer
+         * Copyright (c) 2014 Ion Drive Software Ltd.
+         *
+         * Permission is hereby granted, free of charge, to any person obtaining a copy
+         * of this software and associated documentation files (the "Software"), to deal
+         * in the Software without restriction, including without limitation the rights
+         * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+         * copies of the Software, and to permit persons to whom the Software is
+         * furnished to do so, subject to the following conditions:
+         *
+         * The above copyright notice and this permission notice shall be included in all
+         * copies or substantial portions of the Software.
+         *
+         * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+         * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+         * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+         * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+         * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+         * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+         * SOFTWARE
+         */
+        /**
+         * msgpack implementation highly based on notepack.io
+         * https://github.com/darrachequesne/notepack
+         */
+        function utf8Length(str) {
+            var c = 0, length = 0;
+            for (var i = 0, l = str.length; i < l; i++) {
+                c = str.charCodeAt(i);
+                if (c < 0x80) {
+                    length += 1;
+                }
+                else if (c < 0x800) {
+                    length += 2;
+                }
+                else if (c < 0xd800 || c >= 0xe000) {
+                    length += 3;
+                }
+                else {
+                    i++;
+                    length += 4;
+                }
+            }
+            return length;
+        }
+        function utf8Write(view, offset, str) {
+            var c = 0;
+            for (var i = 0, l = str.length; i < l; i++) {
+                c = str.charCodeAt(i);
+                if (c < 0x80) {
+                    view[offset++] = c;
+                }
+                else if (c < 0x800) {
+                    view[offset++] = 0xc0 | (c >> 6);
+                    view[offset++] = 0x80 | (c & 0x3f);
+                }
+                else if (c < 0xd800 || c >= 0xe000) {
+                    view[offset++] = 0xe0 | (c >> 12);
+                    view[offset++] = 0x80 | (c >> 6 & 0x3f);
+                    view[offset++] = 0x80 | (c & 0x3f);
+                }
+                else {
+                    i++;
+                    c = 0x10000 + (((c & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
+                    view[offset++] = 0xf0 | (c >> 18);
+                    view[offset++] = 0x80 | (c >> 12 & 0x3f);
+                    view[offset++] = 0x80 | (c >> 6 & 0x3f);
+                    view[offset++] = 0x80 | (c & 0x3f);
+                }
+            }
+        }
+        function int8$1(bytes, value) {
+            bytes.push(value & 255);
+        }
+        function uint8$1(bytes, value) {
+            bytes.push(value & 255);
+        }
+        function int16$1(bytes, value) {
+            bytes.push(value & 255);
+            bytes.push((value >> 8) & 255);
+        }
+        function uint16$1(bytes, value) {
+            bytes.push(value & 255);
+            bytes.push((value >> 8) & 255);
+        }
+        function int32$1(bytes, value) {
+            bytes.push(value & 255);
+            bytes.push((value >> 8) & 255);
+            bytes.push((value >> 16) & 255);
+            bytes.push((value >> 24) & 255);
+        }
+        function uint32$1(bytes, value) {
+            var b4 = value >> 24;
+            var b3 = value >> 16;
+            var b2 = value >> 8;
+            var b1 = value;
+            bytes.push(b1 & 255);
+            bytes.push(b2 & 255);
+            bytes.push(b3 & 255);
+            bytes.push(b4 & 255);
+        }
+        function int64$1(bytes, value) {
+            var high = Math.floor(value / Math.pow(2, 32));
+            var low = value >>> 0;
+            uint32$1(bytes, low);
+            uint32$1(bytes, high);
+        }
+        function uint64$1(bytes, value) {
+            var high = (value / Math.pow(2, 32)) >> 0;
+            var low = value >>> 0;
+            uint32$1(bytes, low);
+            uint32$1(bytes, high);
+        }
+        function float32$1(bytes, value) {
+            writeFloat32(bytes, value);
+        }
+        function float64$1(bytes, value) {
+            writeFloat64(bytes, value);
+        }
+        var _int32$1 = new Int32Array(2);
+        var _float32$1 = new Float32Array(_int32$1.buffer);
+        var _float64$1 = new Float64Array(_int32$1.buffer);
+        function writeFloat32(bytes, value) {
+            _float32$1[0] = value;
+            int32$1(bytes, _int32$1[0]);
+        }
+        function writeFloat64(bytes, value) {
+            _float64$1[0] = value;
+            int32$1(bytes, _int32$1[0 ]);
+            int32$1(bytes, _int32$1[1 ]);
+        }
+        function boolean$1(bytes, value) {
+            return uint8$1(bytes, value ? 1 : 0);
+        }
+        function string$1(bytes, value) {
+            // encode `null` strings as empty.
+            if (!value) {
+                value = "";
+            }
+            var length = utf8Length(value);
+            var size = 0;
+            // fixstr
+            if (length < 0x20) {
+                bytes.push(length | 0xa0);
+                size = 1;
+            }
+            // str 8
+            else if (length < 0x100) {
+                bytes.push(0xd9);
+                uint8$1(bytes, length);
+                size = 2;
+            }
+            // str 16
+            else if (length < 0x10000) {
+                bytes.push(0xda);
+                uint16$1(bytes, length);
+                size = 3;
+            }
+            // str 32
+            else if (length < 0x100000000) {
+                bytes.push(0xdb);
+                uint32$1(bytes, length);
+                size = 5;
+            }
+            else {
+                throw new Error('String too long');
+            }
+            utf8Write(bytes, bytes.length, value);
+            return size + length;
+        }
+        function number$1(bytes, value) {
+            if (isNaN(value)) {
+                return number$1(bytes, 0);
+            }
+            else if (!isFinite(value)) {
+                return number$1(bytes, (value > 0) ? Number.MAX_SAFE_INTEGER : -Number.MAX_SAFE_INTEGER);
+            }
+            else if (value !== (value | 0)) {
+                bytes.push(0xcb);
+                writeFloat64(bytes, value);
+                return 9;
+                // TODO: encode float 32?
+                // is it possible to differentiate between float32 / float64 here?
+                // // float 32
+                // bytes.push(0xca);
+                // writeFloat32(bytes, value);
+                // return 5;
+            }
+            if (value >= 0) {
+                // positive fixnum
+                if (value < 0x80) {
+                    uint8$1(bytes, value);
+                    return 1;
+                }
+                // uint 8
+                if (value < 0x100) {
+                    bytes.push(0xcc);
+                    uint8$1(bytes, value);
+                    return 2;
+                }
+                // uint 16
+                if (value < 0x10000) {
+                    bytes.push(0xcd);
+                    uint16$1(bytes, value);
+                    return 3;
+                }
+                // uint 32
+                if (value < 0x100000000) {
+                    bytes.push(0xce);
+                    uint32$1(bytes, value);
+                    return 5;
+                }
+                // uint 64
+                bytes.push(0xcf);
+                uint64$1(bytes, value);
+                return 9;
+            }
+            else {
+                // negative fixnum
+                if (value >= -0x20) {
+                    bytes.push(0xe0 | (value + 0x20));
+                    return 1;
+                }
+                // int 8
+                if (value >= -0x80) {
+                    bytes.push(0xd0);
+                    int8$1(bytes, value);
+                    return 2;
+                }
+                // int 16
+                if (value >= -0x8000) {
+                    bytes.push(0xd1);
+                    int16$1(bytes, value);
+                    return 3;
+                }
+                // int 32
+                if (value >= -0x80000000) {
+                    bytes.push(0xd2);
+                    int32$1(bytes, value);
+                    return 5;
+                }
+                // int 64
+                bytes.push(0xd3);
+                int64$1(bytes, value);
+                return 9;
+            }
+        }
+
+        var encode = /*#__PURE__*/Object.freeze({
+            __proto__: null,
+            utf8Write: utf8Write,
+            int8: int8$1,
+            uint8: uint8$1,
+            int16: int16$1,
+            uint16: uint16$1,
+            int32: int32$1,
+            uint32: uint32$1,
+            int64: int64$1,
+            uint64: uint64$1,
+            float32: float32$1,
+            float64: float64$1,
+            writeFloat32: writeFloat32,
+            writeFloat64: writeFloat64,
+            boolean: boolean$1,
+            string: string$1,
+            number: number$1
+        });
+
+        /**
+         * Copyright (c) 2018 Endel Dreyer
+         * Copyright (c) 2014 Ion Drive Software Ltd.
+         *
+         * Permission is hereby granted, free of charge, to any person obtaining a copy
+         * of this software and associated documentation files (the "Software"), to deal
+         * in the Software without restriction, including without limitation the rights
+         * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+         * copies of the Software, and to permit persons to whom the Software is
+         * furnished to do so, subject to the following conditions:
+         *
+         * The above copyright notice and this permission notice shall be included in all
+         * copies or substantial portions of the Software.
+         *
+         * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+         * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+         * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+         * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+         * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+         * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+         * SOFTWARE
+         */
+        function utf8Read(bytes, offset, length) {
+            var string = '', chr = 0;
+            for (var i = offset, end = offset + length; i < end; i++) {
+                var byte = bytes[i];
+                if ((byte & 0x80) === 0x00) {
+                    string += String.fromCharCode(byte);
+                    continue;
+                }
+                if ((byte & 0xe0) === 0xc0) {
+                    string += String.fromCharCode(((byte & 0x1f) << 6) |
+                        (bytes[++i] & 0x3f));
+                    continue;
+                }
+                if ((byte & 0xf0) === 0xe0) {
+                    string += String.fromCharCode(((byte & 0x0f) << 12) |
+                        ((bytes[++i] & 0x3f) << 6) |
+                        ((bytes[++i] & 0x3f) << 0));
+                    continue;
+                }
+                if ((byte & 0xf8) === 0xf0) {
+                    chr = ((byte & 0x07) << 18) |
+                        ((bytes[++i] & 0x3f) << 12) |
+                        ((bytes[++i] & 0x3f) << 6) |
+                        ((bytes[++i] & 0x3f) << 0);
+                    if (chr >= 0x010000) { // surrogate pair
+                        chr -= 0x010000;
+                        string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00);
+                    }
+                    else {
+                        string += String.fromCharCode(chr);
+                    }
+                    continue;
+                }
+                console.error('Invalid byte ' + byte.toString(16));
+                // (do not throw error to avoid server/client from crashing due to hack attemps)
+                // throw new Error('Invalid byte ' + byte.toString(16));
+            }
+            return string;
+        }
+        function int8(bytes, it) {
+            return uint8(bytes, it) << 24 >> 24;
+        }
+        function uint8(bytes, it) {
+            return bytes[it.offset++];
+        }
+        function int16(bytes, it) {
+            return uint16(bytes, it) << 16 >> 16;
+        }
+        function uint16(bytes, it) {
+            return bytes[it.offset++] | bytes[it.offset++] << 8;
+        }
+        function int32(bytes, it) {
+            return bytes[it.offset++] | bytes[it.offset++] << 8 | bytes[it.offset++] << 16 | bytes[it.offset++] << 24;
+        }
+        function uint32(bytes, it) {
+            return int32(bytes, it) >>> 0;
+        }
+        function float32(bytes, it) {
+            return readFloat32(bytes, it);
+        }
+        function float64(bytes, it) {
+            return readFloat64(bytes, it);
+        }
+        function int64(bytes, it) {
+            var low = uint32(bytes, it);
+            var high = int32(bytes, it) * Math.pow(2, 32);
+            return high + low;
+        }
+        function uint64(bytes, it) {
+            var low = uint32(bytes, it);
+            var high = uint32(bytes, it) * Math.pow(2, 32);
+            return high + low;
+        }
+        var _int32 = new Int32Array(2);
+        var _float32 = new Float32Array(_int32.buffer);
+        var _float64 = new Float64Array(_int32.buffer);
+        function readFloat32(bytes, it) {
+            _int32[0] = int32(bytes, it);
+            return _float32[0];
+        }
+        function readFloat64(bytes, it) {
+            _int32[0 ] = int32(bytes, it);
+            _int32[1 ] = int32(bytes, it);
+            return _float64[0];
+        }
+        function boolean(bytes, it) {
+            return uint8(bytes, it) > 0;
+        }
+        function string(bytes, it) {
+            var prefix = bytes[it.offset++];
+            var length;
+            if (prefix < 0xc0) {
+                // fixstr
+                length = prefix & 0x1f;
+            }
+            else if (prefix === 0xd9) {
+                length = uint8(bytes, it);
+            }
+            else if (prefix === 0xda) {
+                length = uint16(bytes, it);
+            }
+            else if (prefix === 0xdb) {
+                length = uint32(bytes, it);
+            }
+            var value = utf8Read(bytes, it.offset, length);
+            it.offset += length;
+            return value;
+        }
+        function stringCheck(bytes, it) {
+            var prefix = bytes[it.offset];
+            return (
+            // fixstr
+            (prefix < 0xc0 && prefix > 0xa0) ||
+                // str 8
+                prefix === 0xd9 ||
+                // str 16
+                prefix === 0xda ||
+                // str 32
+                prefix === 0xdb);
+        }
+        function number(bytes, it) {
+            var prefix = bytes[it.offset++];
+            if (prefix < 0x80) {
+                // positive fixint
+                return prefix;
+            }
+            else if (prefix === 0xca) {
+                // float 32
+                return readFloat32(bytes, it);
+            }
+            else if (prefix === 0xcb) {
+                // float 64
+                return readFloat64(bytes, it);
+            }
+            else if (prefix === 0xcc) {
+                // uint 8
+                return uint8(bytes, it);
+            }
+            else if (prefix === 0xcd) {
+                // uint 16
+                return uint16(bytes, it);
+            }
+            else if (prefix === 0xce) {
+                // uint 32
+                return uint32(bytes, it);
+            }
+            else if (prefix === 0xcf) {
+                // uint 64
+                return uint64(bytes, it);
+            }
+            else if (prefix === 0xd0) {
+                // int 8
+                return int8(bytes, it);
+            }
+            else if (prefix === 0xd1) {
+                // int 16
+                return int16(bytes, it);
+            }
+            else if (prefix === 0xd2) {
+                // int 32
+                return int32(bytes, it);
+            }
+            else if (prefix === 0xd3) {
+                // int 64
+                return int64(bytes, it);
+            }
+            else if (prefix > 0xdf) {
+                // negative fixint
+                return (0xff - prefix + 1) * -1;
+            }
+        }
+        function numberCheck(bytes, it) {
+            var prefix = bytes[it.offset];
+            // positive fixint - 0x00 - 0x7f
+            // float 32        - 0xca
+            // float 64        - 0xcb
+            // uint 8          - 0xcc
+            // uint 16         - 0xcd
+            // uint 32         - 0xce
+            // uint 64         - 0xcf
+            // int 8           - 0xd0
+            // int 16          - 0xd1
+            // int 32          - 0xd2
+            // int 64          - 0xd3
+            return (prefix < 0x80 ||
+                (prefix >= 0xca && prefix <= 0xd3));
+        }
+        function arrayCheck(bytes, it) {
+            return bytes[it.offset] < 0xa0;
+            // const prefix = bytes[it.offset] ;
+            // if (prefix < 0xa0) {
+            //   return prefix;
+            // // array
+            // } else if (prefix === 0xdc) {
+            //   it.offset += 2;
+            // } else if (0xdd) {
+            //   it.offset += 4;
+            // }
+            // return prefix;
+        }
+        function switchStructureCheck(bytes, it) {
+            return (
+            // previous byte should be `SWITCH_TO_STRUCTURE`
+            bytes[it.offset - 1] === SWITCH_TO_STRUCTURE &&
+                // next byte should be a number
+                (bytes[it.offset] < 0x80 || (bytes[it.offset] >= 0xca && bytes[it.offset] <= 0xd3)));
+        }
+
+        var decode = /*#__PURE__*/Object.freeze({
+            __proto__: null,
+            int8: int8,
+            uint8: uint8,
+            int16: int16,
+            uint16: uint16,
+            int32: int32,
+            uint32: uint32,
+            float32: float32,
+            float64: float64,
+            int64: int64,
+            uint64: uint64,
+            readFloat32: readFloat32,
+            readFloat64: readFloat64,
+            boolean: boolean,
+            string: string,
+            stringCheck: stringCheck,
+            number: number,
+            numberCheck: numberCheck,
+            arrayCheck: arrayCheck,
+            switchStructureCheck: switchStructureCheck
+        });
+
+        var CollectionSchema = /** @class */ (function () {
+            function CollectionSchema(initialValues) {
+                var _this = this;
+                this.$changes = new ChangeTree(this);
+                this.$items = new Map();
+                this.$indexes = new Map();
+                this.$refId = 0;
+                if (initialValues) {
+                    initialValues.forEach(function (v) { return _this.add(v); });
+                }
+            }
+            CollectionSchema.prototype.onAdd = function (callback, triggerAll) {
+                if (triggerAll === void 0) { triggerAll = true; }
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.ADD, callback, (triggerAll)
+                    ? this.$items
+                    : undefined);
+            };
+            CollectionSchema.prototype.onRemove = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.DELETE, callback); };
+            CollectionSchema.prototype.onChange = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.REPLACE, callback); };
+            CollectionSchema.is = function (type) {
+                return type['collection'] !== undefined;
+            };
+            CollectionSchema.prototype.add = function (value) {
+                // set "index" for reference.
+                var index = this.$refId++;
+                var isRef = (value['$changes']) !== undefined;
+                if (isRef) {
+                    value['$changes'].setParent(this, this.$changes.root, index);
+                }
+                this.$changes.indexes[index] = index;
+                this.$indexes.set(index, index);
+                this.$items.set(index, value);
+                this.$changes.change(index);
+                return index;
+            };
+            CollectionSchema.prototype.at = function (index) {
+                var key = Array.from(this.$items.keys())[index];
+                return this.$items.get(key);
+            };
+            CollectionSchema.prototype.entries = function () {
+                return this.$items.entries();
+            };
+            CollectionSchema.prototype.delete = function (item) {
+                var entries = this.$items.entries();
+                var index;
+                var entry;
+                while (entry = entries.next()) {
+                    if (entry.done) {
+                        break;
+                    }
+                    if (item === entry.value[1]) {
+                        index = entry.value[0];
+                        break;
+                    }
+                }
+                if (index === undefined) {
+                    return false;
+                }
+                this.$changes.delete(index);
+                this.$indexes.delete(index);
+                return this.$items.delete(index);
+            };
+            CollectionSchema.prototype.clear = function (changes) {
+                // discard previous operations.
+                this.$changes.discard(true, true);
+                this.$changes.indexes = {};
+                // clear previous indexes
+                this.$indexes.clear();
+                //
+                // When decoding:
+                // - enqueue items for DELETE callback.
+                // - flag child items for garbage collection.
+                //
+                if (changes) {
+                    removeChildRefs.call(this, changes);
+                }
+                // clear items
+                this.$items.clear();
+                this.$changes.operation({ index: 0, op: exports.OPERATION.CLEAR });
+                // touch all structures until reach root
+                this.$changes.touchParents();
+            };
+            CollectionSchema.prototype.has = function (value) {
+                return Array.from(this.$items.values()).some(function (v) { return v === value; });
+            };
+            CollectionSchema.prototype.forEach = function (callbackfn) {
+                var _this = this;
+                this.$items.forEach(function (value, key, _) { return callbackfn(value, key, _this); });
+            };
+            CollectionSchema.prototype.values = function () {
+                return this.$items.values();
+            };
+            Object.defineProperty(CollectionSchema.prototype, "size", {
+                get: function () {
+                    return this.$items.size;
+                },
+                enumerable: false,
+                configurable: true
+            });
+            CollectionSchema.prototype.setIndex = function (index, key) {
+                this.$indexes.set(index, key);
+            };
+            CollectionSchema.prototype.getIndex = function (index) {
+                return this.$indexes.get(index);
+            };
+            CollectionSchema.prototype.getByIndex = function (index) {
+                return this.$items.get(this.$indexes.get(index));
+            };
+            CollectionSchema.prototype.deleteByIndex = function (index) {
+                var key = this.$indexes.get(index);
+                this.$items.delete(key);
+                this.$indexes.delete(index);
+            };
+            CollectionSchema.prototype.toArray = function () {
+                return Array.from(this.$items.values());
+            };
+            CollectionSchema.prototype.toJSON = function () {
+                var values = [];
+                this.forEach(function (value, key) {
+                    values.push((typeof (value['toJSON']) === "function")
+                        ? value['toJSON']()
+                        : value);
+                });
+                return values;
+            };
+            //
+            // Decoding utilities
+            //
+            CollectionSchema.prototype.clone = function (isDecoding) {
+                var cloned;
+                if (isDecoding) {
+                    // client-side
+                    cloned = Object.assign(new CollectionSchema(), this);
+                }
+                else {
+                    // server-side
+                    cloned = new CollectionSchema();
+                    this.forEach(function (value) {
+                        if (value['$changes']) {
+                            cloned.add(value['clone']());
+                        }
+                        else {
+                            cloned.add(value);
+                        }
+                    });
+                }
+                return cloned;
+            };
+            return CollectionSchema;
+        }());
+
+        var SetSchema = /** @class */ (function () {
+            function SetSchema(initialValues) {
+                var _this = this;
+                this.$changes = new ChangeTree(this);
+                this.$items = new Map();
+                this.$indexes = new Map();
+                this.$refId = 0;
+                if (initialValues) {
+                    initialValues.forEach(function (v) { return _this.add(v); });
+                }
+            }
+            SetSchema.prototype.onAdd = function (callback, triggerAll) {
+                if (triggerAll === void 0) { triggerAll = true; }
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.ADD, callback, (triggerAll)
+                    ? this.$items
+                    : undefined);
+            };
+            SetSchema.prototype.onRemove = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.DELETE, callback); };
+            SetSchema.prototype.onChange = function (callback) { return addCallback(this.$callbacks || (this.$callbacks = []), exports.OPERATION.REPLACE, callback); };
+            SetSchema.is = function (type) {
+                return type['set'] !== undefined;
+            };
+            SetSchema.prototype.add = function (value) {
+                var _a, _b;
+                // immediatelly return false if value already added.
+                if (this.has(value)) {
+                    return false;
+                }
+                // set "index" for reference.
+                var index = this.$refId++;
+                if ((value['$changes']) !== undefined) {
+                    value['$changes'].setParent(this, this.$changes.root, index);
+                }
+                var operation = (_b = (_a = this.$changes.indexes[index]) === null || _a === void 0 ? void 0 : _a.op) !== null && _b !== void 0 ? _b : exports.OPERATION.ADD;
+                this.$changes.indexes[index] = index;
+                this.$indexes.set(index, index);
+                this.$items.set(index, value);
+                this.$changes.change(index, operation);
+                return index;
+            };
+            SetSchema.prototype.entries = function () {
+                return this.$items.entries();
+            };
+            SetSchema.prototype.delete = function (item) {
+                var entries = this.$items.entries();
+                var index;
+                var entry;
+                while (entry = entries.next()) {
+                    if (entry.done) {
+                        break;
+                    }
+                    if (item === entry.value[1]) {
+                        index = entry.value[0];
+                        break;
+                    }
+                }
+                if (index === undefined) {
+                    return false;
+                }
+                this.$changes.delete(index);
+                this.$indexes.delete(index);
+                return this.$items.delete(index);
+            };
+            SetSchema.prototype.clear = function (changes) {
+                // discard previous operations.
+                this.$changes.discard(true, true);
+                this.$changes.indexes = {};
+                // clear previous indexes
+                this.$indexes.clear();
+                //
+                // When decoding:
+                // - enqueue items for DELETE callback.
+                // - flag child items for garbage collection.
+                //
+                if (changes) {
+                    removeChildRefs.call(this, changes);
+                }
+                // clear items
+                this.$items.clear();
+                this.$changes.operation({ index: 0, op: exports.OPERATION.CLEAR });
+                // touch all structures until reach root
+                this.$changes.touchParents();
+            };
+            SetSchema.prototype.has = function (value) {
+                var values = this.$items.values();
+                var has = false;
+                var entry;
+                while (entry = values.next()) {
+                    if (entry.done) {
+                        break;
+                    }
+                    if (value === entry.value) {
+                        has = true;
+                        break;
+                    }
+                }
+                return has;
+            };
+            SetSchema.prototype.forEach = function (callbackfn) {
+                var _this = this;
+                this.$items.forEach(function (value, key, _) { return callbackfn(value, key, _this); });
+            };
+            SetSchema.prototype.values = function () {
+                return this.$items.values();
+            };
+            Object.defineProperty(SetSchema.prototype, "size", {
+                get: function () {
+                    return this.$items.size;
+                },
+                enumerable: false,
+                configurable: true
+            });
+            SetSchema.prototype.setIndex = function (index, key) {
+                this.$indexes.set(index, key);
+            };
+            SetSchema.prototype.getIndex = function (index) {
+                return this.$indexes.get(index);
+            };
+            SetSchema.prototype.getByIndex = function (index) {
+                return this.$items.get(this.$indexes.get(index));
+            };
+            SetSchema.prototype.deleteByIndex = function (index) {
+                var key = this.$indexes.get(index);
+                this.$items.delete(key);
+                this.$indexes.delete(index);
+            };
+            SetSchema.prototype.toArray = function () {
+                return Array.from(this.$items.values());
+            };
+            SetSchema.prototype.toJSON = function () {
+                var values = [];
+                this.forEach(function (value, key) {
+                    values.push((typeof (value['toJSON']) === "function")
+                        ? value['toJSON']()
+                        : value);
+                });
+                return values;
+            };
+            //
+            // Decoding utilities
+            //
+            SetSchema.prototype.clone = function (isDecoding) {
+                var cloned;
+                if (isDecoding) {
+                    // client-side
+                    cloned = Object.assign(new SetSchema(), this);
+                }
+                else {
+                    // server-side
+                    cloned = new SetSchema();
+                    this.forEach(function (value) {
+                        if (value['$changes']) {
+                            cloned.add(value['clone']());
+                        }
+                        else {
+                            cloned.add(value);
+                        }
+                    });
+                }
+                return cloned;
+            };
+            return SetSchema;
+        }());
+
+        var ClientState = /** @class */ (function () {
+            function ClientState() {
+                this.refIds = new WeakSet();
+                this.containerIndexes = new WeakMap();
+            }
+            // containerIndexes = new Map<ChangeTree, Set<number>>();
+            ClientState.prototype.addRefId = function (changeTree) {
+                if (!this.refIds.has(changeTree)) {
+                    this.refIds.add(changeTree);
+                    this.containerIndexes.set(changeTree, new Set());
+                }
+            };
+            ClientState.get = function (client) {
+                if (client.$filterState === undefined) {
+                    client.$filterState = new ClientState();
+                }
+                return client.$filterState;
+            };
+            return ClientState;
+        }());
+
+        var ReferenceTracker = /** @class */ (function () {
+            function ReferenceTracker() {
+                //
+                // Relation of refId => Schema structure
+                // For direct access of structures during decoding time.
+                //
+                this.refs = new Map();
+                this.refCounts = {};
+                this.deletedRefs = new Set();
+                this.nextUniqueId = 0;
+            }
+            ReferenceTracker.prototype.getNextUniqueId = function () {
+                return this.nextUniqueId++;
+            };
+            // for decoding
+            ReferenceTracker.prototype.addRef = function (refId, ref, incrementCount) {
+                if (incrementCount === void 0) { incrementCount = true; }
+                this.refs.set(refId, ref);
+                if (incrementCount) {
+                    this.refCounts[refId] = (this.refCounts[refId] || 0) + 1;
+                }
+            };
+            // for decoding
+            ReferenceTracker.prototype.removeRef = function (refId) {
+                this.refCounts[refId] = this.refCounts[refId] - 1;
+                this.deletedRefs.add(refId);
+            };
+            ReferenceTracker.prototype.clearRefs = function () {
+                this.refs.clear();
+                this.deletedRefs.clear();
+                this.refCounts = {};
+            };
+            // for decoding
+            ReferenceTracker.prototype.garbageCollectDeletedRefs = function () {
+                var _this = this;
+                this.deletedRefs.forEach(function (refId) {
+                    //
+                    // Skip active references.
+                    //
+                    if (_this.refCounts[refId] > 0) {
+                        return;
+                    }
+                    var ref = _this.refs.get(refId);
+                    //
+                    // Ensure child schema instances have their references removed as well.
+                    //
+                    if (ref instanceof Schema) {
+                        for (var fieldName in ref['_definition'].schema) {
+                            if (typeof (ref['_definition'].schema[fieldName]) !== "string" &&
+                                ref[fieldName] &&
+                                ref[fieldName]['$changes']) {
+                                _this.removeRef(ref[fieldName]['$changes'].refId);
+                            }
+                        }
+                    }
+                    else {
+                        var definition = ref['$changes'].parent._definition;
+                        var type = definition.schema[definition.fieldsByIndex[ref['$changes'].parentIndex]];
+                        if (typeof (Object.values(type)[0]) === "function") {
+                            Array.from(ref.values())
+                                .forEach(function (child) { return _this.removeRef(child['$changes'].refId); });
+                        }
+                    }
+                    _this.refs.delete(refId);
+                    delete _this.refCounts[refId];
+                });
+                // clear deleted refs.
+                this.deletedRefs.clear();
+            };
+            return ReferenceTracker;
+        }());
+
+        var EncodeSchemaError = /** @class */ (function (_super) {
+            __extends(EncodeSchemaError, _super);
+            function EncodeSchemaError() {
+                return _super !== null && _super.apply(this, arguments) || this;
+            }
+            return EncodeSchemaError;
+        }(Error));
+        function assertType(value, type, klass, field) {
+            var typeofTarget;
+            var allowNull = false;
+            switch (type) {
+                case "number":
+                case "int8":
+                case "uint8":
+                case "int16":
+                case "uint16":
+                case "int32":
+                case "uint32":
+                case "int64":
+                case "uint64":
+                case "float32":
+                case "float64":
+                    typeofTarget = "number";
+                    if (isNaN(value)) {
+                        console.log("trying to encode \"NaN\" in ".concat(klass.constructor.name, "#").concat(field));
+                    }
+                    break;
+                case "string":
+                    typeofTarget = "string";
+                    allowNull = true;
+                    break;
+                case "boolean":
+                    // boolean is always encoded as true/false based on truthiness
+                    return;
+            }
+            if (typeof (value) !== typeofTarget && (!allowNull || (allowNull && value !== null))) {
+                var foundValue = "'".concat(JSON.stringify(value), "'").concat((value && value.constructor && " (".concat(value.constructor.name, ")")) || '');
+                throw new EncodeSchemaError("a '".concat(typeofTarget, "' was expected, but ").concat(foundValue, " was provided in ").concat(klass.constructor.name, "#").concat(field));
+            }
+        }
+        function assertInstanceType(value, type, klass, field) {
+            if (!(value instanceof type)) {
+                throw new EncodeSchemaError("a '".concat(type.name, "' was expected, but '").concat(value.constructor.name, "' was provided in ").concat(klass.constructor.name, "#").concat(field));
+            }
+        }
+        function encodePrimitiveType(type, bytes, value, klass, field) {
+            assertType(value, type, klass, field);
+            var encodeFunc = encode[type];
+            if (encodeFunc) {
+                encodeFunc(bytes, value);
+            }
+            else {
+                throw new EncodeSchemaError("a '".concat(type, "' was expected, but ").concat(value, " was provided in ").concat(klass.constructor.name, "#").concat(field));
+            }
+        }
+        function decodePrimitiveType(type, bytes, it) {
+            return decode[type](bytes, it);
+        }
+        /**
+         * Schema encoder / decoder
+         */
+        var Schema = /** @class */ (function () {
+            // allow inherited classes to have a constructor
+            function Schema() {
+                var args = [];
+                for (var _i = 0; _i < arguments.length; _i++) {
+                    args[_i] = arguments[_i];
+                }
+                // fix enumerability of fields for end-user
+                Object.defineProperties(this, {
+                    $changes: {
+                        value: new ChangeTree(this, undefined, new ReferenceTracker()),
+                        enumerable: false,
+                        writable: true
+                    },
+                    // $listeners: {
+                    //     value: undefined,
+                    //     enumerable: false,
+                    //     writable: true
+                    // },
+                    $callbacks: {
+                        value: undefined,
+                        enumerable: false,
+                        writable: true
+                    },
+                });
+                var descriptors = this._definition.descriptors;
+                if (descriptors) {
+                    Object.defineProperties(this, descriptors);
+                }
+                //
+                // Assign initial values
+                //
+                if (args[0]) {
+                    this.assign(args[0]);
+                }
+            }
+            Schema.onError = function (e) {
+                console.error(e);
+            };
+            Schema.is = function (type) {
+                return (type['_definition'] &&
+                    type['_definition'].schema !== undefined);
+            };
+            Schema.prototype.onChange = function (callback) {
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.REPLACE, callback);
+            };
+            Schema.prototype.onRemove = function (callback) {
+                return addCallback((this.$callbacks || (this.$callbacks = [])), exports.OPERATION.DELETE, callback);
+            };
+            Schema.prototype.assign = function (props) {
+                Object.assign(this, props);
+                return this;
+            };
+            Object.defineProperty(Schema.prototype, "_definition", {
+                get: function () { return this.constructor._definition; },
+                enumerable: false,
+                configurable: true
+            });
+            /**
+             * (Server-side): Flag a property to be encoded for the next patch.
+             * @param instance Schema instance
+             * @param property string representing the property name, or number representing the index of the property.
+             * @param operation OPERATION to perform (detected automatically)
+             */
+            Schema.prototype.setDirty = function (property, operation) {
+                this.$changes.change(property, operation);
+            };
+            /**
+             * Client-side: listen for changes on property.
+             * @param prop the property name
+             * @param callback callback to be triggered on property change
+             * @param immediate trigger immediatelly if property has been already set.
+             */
+            Schema.prototype.listen = function (prop, callback, immediate) {
+                var _this = this;
+                if (immediate === void 0) { immediate = true; }
+                if (!this.$callbacks) {
+                    this.$callbacks = {};
+                }
+                if (!this.$callbacks[prop]) {
+                    this.$callbacks[prop] = [];
+                }
+                this.$callbacks[prop].push(callback);
+                if (immediate && this[prop] !== undefined) {
+                    callback(this[prop], undefined);
+                }
+                // return un-register callback.
+                return function () { return spliceOne(_this.$callbacks[prop], _this.$callbacks[prop].indexOf(callback)); };
+            };
+            Schema.prototype.decode = function (bytes, it, ref) {
+                var _a;
+                if (it === void 0) { it = { offset: 0 }; }
+                if (ref === void 0) { ref = this; }
+                var allChanges = [];
+                var $root = this.$changes.root;
+                var totalBytes = bytes.length;
+                var refId = 0;
+                $root.refs.set(refId, this);
+                while (it.offset < totalBytes) {
+                    var byte = bytes[it.offset++];
+                    if (byte == SWITCH_TO_STRUCTURE) {
+                        refId = number(bytes, it);
+                        var nextRef = $root.refs.get(refId);
+                        //
+                        // Trying to access a reference that haven't been decoded yet.
+                        //
+                        if (!nextRef) {
+                            throw new Error("\"refId\" not found: ".concat(refId));
+                        }
+                        ref = nextRef;
+                        continue;
+                    }
+                    var changeTree = ref['$changes'];
+                    var isSchema = (ref['_definition'] !== undefined);
+                    var operation = (isSchema)
+                        ? (byte >> 6) << 6 // "compressed" index + operation
+                        : byte; // "uncompressed" index + operation (array/map items)
+                    if (operation === exports.OPERATION.CLEAR) {
+                        //
+                        // TODO: refactor me!
+                        // The `.clear()` method is calling `$root.removeRef(refId)` for
+                        // each item inside this collection
+                        //
+                        ref.clear(allChanges);
+                        continue;
+                    }
+                    var fieldIndex = (isSchema)
+                        ? byte % (operation || 255) // if "REPLACE" operation (0), use 255
+                        : number(bytes, it);
+                    var fieldName = (isSchema)
+                        ? (ref['_definition'].fieldsByIndex[fieldIndex])
+                        : "";
+                    var type = changeTree.getType(fieldIndex);
+                    var value = void 0;
+                    var previousValue = void 0;
+                    var dynamicIndex = void 0;
+                    if (!isSchema) {
+                        previousValue = ref['getByIndex'](fieldIndex);
+                        if ((operation & exports.OPERATION.ADD) === exports.OPERATION.ADD) { // ADD or DELETE_AND_ADD
+                            dynamicIndex = (ref instanceof MapSchema)
+                                ? string(bytes, it)
+                                : fieldIndex;
+                            ref['setIndex'](fieldIndex, dynamicIndex);
+                        }
+                        else {
+                            // here
+                            dynamicIndex = ref['getIndex'](fieldIndex);
+                        }
+                    }
+                    else {
+                        previousValue = ref["_".concat(fieldName)];
+                    }
+                    //
+                    // Delete operations
+                    //
+                    if ((operation & exports.OPERATION.DELETE) === exports.OPERATION.DELETE) {
+                        if (operation !== exports.OPERATION.DELETE_AND_ADD) {
+                            ref['deleteByIndex'](fieldIndex);
+                        }
+                        // Flag `refId` for garbage collection.
+                        if (previousValue && previousValue['$changes']) {
+                            $root.removeRef(previousValue['$changes'].refId);
+                        }
+                        value = null;
+                    }
+                    if (fieldName === undefined) {
+                        console.warn("@colyseus/schema: definition mismatch");
+                        //
+                        // keep skipping next bytes until reaches a known structure
+                        // by local decoder.
+                        //
+                        var nextIterator = { offset: it.offset };
+                        while (it.offset < totalBytes) {
+                            if (switchStructureCheck(bytes, it)) {
+                                nextIterator.offset = it.offset + 1;
+                                if ($root.refs.has(number(bytes, nextIterator))) {
+                                    break;
+                                }
+                            }
+                            it.offset++;
+                        }
+                        continue;
+                    }
+                    else if (operation === exports.OPERATION.DELETE) ;
+                    else if (Schema.is(type)) {
+                        var refId_1 = number(bytes, it);
+                        value = $root.refs.get(refId_1);
+                        if (operation !== exports.OPERATION.REPLACE) {
+                            var childType = this.getSchemaType(bytes, it, type);
+                            if (!value) {
+                                value = this.createTypeInstance(childType);
+                                value.$changes.refId = refId_1;
+                                if (previousValue) {
+                                    value.$callbacks = previousValue.$callbacks;
+                                    // value.$listeners = previousValue.$listeners;
+                                    if (previousValue['$changes'].refId &&
+                                        refId_1 !== previousValue['$changes'].refId) {
+                                        $root.removeRef(previousValue['$changes'].refId);
+                                    }
+                                }
+                            }
+                            $root.addRef(refId_1, value, (value !== previousValue));
+                        }
+                    }
+                    else if (typeof (type) === "string") {
+                        //
+                        // primitive value (number, string, boolean, etc)
+                        //
+                        value = decodePrimitiveType(type, bytes, it);
+                    }
+                    else {
+                        var typeDef = getType(Object.keys(type)[0]);
+                        var refId_2 = number(bytes, it);
+                        var valueRef = ($root.refs.has(refId_2))
+                            ? previousValue || $root.refs.get(refId_2)
+                            : new typeDef.constructor();
+                        value = valueRef.clone(true);
+                        value.$changes.refId = refId_2;
+                        // preserve schema callbacks
+                        if (previousValue) {
+                            value['$callbacks'] = previousValue['$callbacks'];
+                            if (previousValue['$changes'].refId &&
+                                refId_2 !== previousValue['$changes'].refId) {
+                                $root.removeRef(previousValue['$changes'].refId);
+                                //
+                                // Trigger onRemove if structure has been replaced.
+                                //
+                                var entries = previousValue.entries();
+                                var iter = void 0;
+                                while ((iter = entries.next()) && !iter.done) {
+                                    var key = (_a = iter.value, _a[0]), value_1 = _a[1];
+                                    allChanges.push({
+                                        refId: refId_2,
+                                        op: exports.OPERATION.DELETE,
+                                        field: key,
+                                        value: undefined,
+                                        previousValue: value_1,
+                                    });
+                                }
+                            }
+                        }
+                        $root.addRef(refId_2, value, (valueRef !== previousValue));
+                    }
+                    if (value !== null &&
+                        value !== undefined) {
+                        if (value['$changes']) {
+                            value['$changes'].setParent(changeTree.ref, changeTree.root, fieldIndex);
+                        }
+                        if (ref instanceof Schema) {
+                            ref[fieldName] = value;
+                            // ref[`_${fieldName}`] = value;
+                        }
+                        else if (ref instanceof MapSchema) {
+                            // const key = ref['$indexes'].get(field);
+                            var key = dynamicIndex;
+                            // ref.set(key, value);
+                            ref['$items'].set(key, value);
+                            ref['$changes'].allChanges.add(fieldIndex);
+                        }
+                        else if (ref instanceof ArraySchema) {
+                            // const key = ref['$indexes'][field];
+                            // console.log("SETTING FOR ArraySchema =>", { field, key, value });
+                            // ref[key] = value;
+                            ref.setAt(fieldIndex, value);
+                        }
+                        else if (ref instanceof CollectionSchema) {
+                            var index = ref.add(value);
+                            ref['setIndex'](fieldIndex, index);
+                        }
+                        else if (ref instanceof SetSchema) {
+                            var index = ref.add(value);
+                            if (index !== false) {
+                                ref['setIndex'](fieldIndex, index);
+                            }
+                        }
+                    }
+                    if (previousValue !== value) {
+                        allChanges.push({
+                            refId: refId,
+                            op: operation,
+                            field: fieldName,
+                            dynamicIndex: dynamicIndex,
+                            value: value,
+                            previousValue: previousValue,
+                        });
+                    }
+                }
+                this._triggerChanges(allChanges);
+                // drop references of unused schemas
+                $root.garbageCollectDeletedRefs();
+                return allChanges;
+            };
+            Schema.prototype.encode = function (encodeAll, bytes, useFilters) {
+                if (encodeAll === void 0) { encodeAll = false; }
+                if (bytes === void 0) { bytes = []; }
+                if (useFilters === void 0) { useFilters = false; }
+                var rootChangeTree = this.$changes;
+                var refIdsVisited = new WeakSet();
+                var changeTrees = [rootChangeTree];
+                var numChangeTrees = 1;
+                for (var i = 0; i < numChangeTrees; i++) {
+                    var changeTree = changeTrees[i];
+                    var ref = changeTree.ref;
+                    var isSchema = (ref instanceof Schema);
+                    // Generate unique refId for the ChangeTree.
+                    changeTree.ensureRefId();
+                    // mark this ChangeTree as visited.
+                    refIdsVisited.add(changeTree);
+                    // root `refId` is skipped.
+                    if (changeTree !== rootChangeTree &&
+                        (changeTree.changed || encodeAll)) {
+                        uint8$1(bytes, SWITCH_TO_STRUCTURE);
+                        number$1(bytes, changeTree.refId);
+                    }
+                    var changes = (encodeAll)
+                        ? Array.from(changeTree.allChanges)
+                        : Array.from(changeTree.changes.values());
+                    for (var j = 0, cl = changes.length; j < cl; j++) {
+                        var operation = (encodeAll)
+                            ? { op: exports.OPERATION.ADD, index: changes[j] }
+                            : changes[j];
+                        var fieldIndex = operation.index;
+                        var field = (isSchema)
+                            ? ref['_definition'].fieldsByIndex && ref['_definition'].fieldsByIndex[fieldIndex]
+                            : fieldIndex;
+                        // cache begin index if `useFilters`
+                        var beginIndex = bytes.length;
+                        // encode field index + operation
+                        if (operation.op !== exports.OPERATION.TOUCH) {
+                            if (isSchema) {
+                                //
+                                // Compress `fieldIndex` + `operation` into a single byte.
+                                // This adds a limitaion of 64 fields per Schema structure
+                                //
+                                uint8$1(bytes, (fieldIndex | operation.op));
+                            }
+                            else {
+                                uint8$1(bytes, operation.op);
+                                // custom operations
+                                if (operation.op === exports.OPERATION.CLEAR) {
+                                    continue;
+                                }
+                                // indexed operations
+                                number$1(bytes, fieldIndex);
+                            }
+                        }
+                        //
+                        // encode "alias" for dynamic fields (maps)
+                        //
+                        if (!isSchema &&
+                            (operation.op & exports.OPERATION.ADD) == exports.OPERATION.ADD // ADD or DELETE_AND_ADD
+                        ) {
+                            if (ref instanceof MapSchema) {
+                                //
+                                // MapSchema dynamic key
+                                //
+                                var dynamicIndex = changeTree.ref['$indexes'].get(fieldIndex);
+                                string$1(bytes, dynamicIndex);
+                            }
+                        }
+                        if (operation.op === exports.OPERATION.DELETE) {
+                            //
+                            // TODO: delete from filter cache data.
+                            //
+                            // if (useFilters) {
+                            //     delete changeTree.caches[fieldIndex];
+                            // }
+                            continue;
+                        }
+                        // const type = changeTree.childType || ref._schema[field];
+                        var type = changeTree.getType(fieldIndex);
+                        // const type = changeTree.getType(fieldIndex);
+                        var value = changeTree.getValue(fieldIndex);
+                        // Enqueue ChangeTree to be visited
+                        if (value &&
+                            value['$changes'] &&
+                            !refIdsVisited.has(value['$changes'])) {
+                            changeTrees.push(value['$changes']);
+                            value['$changes'].ensureRefId();
+                            numChangeTrees++;
+                        }
+                        if (operation.op === exports.OPERATION.TOUCH) {
+                            continue;
+                        }
+                        if (Schema.is(type)) {
+                            assertInstanceType(value, type, ref, field);
+                            //
+                            // Encode refId for this instance.
+                            // The actual instance is going to be encoded on next `changeTree` iteration.
+                            //
+                            number$1(bytes, value.$changes.refId);
+                            // Try to encode inherited TYPE_ID if it's an ADD operation.
+                            if ((operation.op & exports.OPERATION.ADD) === exports.OPERATION.ADD) {
+                                this.tryEncodeTypeId(bytes, type, value.constructor);
+                            }
+                        }
+                        else if (typeof (type) === "string") {
+                            //
+                            // Primitive values
+                            //
+                            encodePrimitiveType(type, bytes, value, ref, field);
+                        }
+                        else {
+                            //
+                            // Custom type (MapSchema, ArraySchema, etc)
+                            //
+                            var definition = getType(Object.keys(type)[0]);
+                            //
+                            // ensure a ArraySchema has been provided
+                            //
+                            assertInstanceType(ref["_".concat(field)], definition.constructor, ref, field);
+                            //
+                            // Encode refId for this instance.
+                            // The actual instance is going to be encoded on next `changeTree` iteration.
+                            //
+                            number$1(bytes, value.$changes.refId);
+                        }
+                        if (useFilters) {
+                            // cache begin / end index
+                            changeTree.cache(fieldIndex, bytes.slice(beginIndex));
+                        }
+                    }
+                    if (!encodeAll && !useFilters) {
+                        changeTree.discard();
+                    }
+                }
+                return bytes;
+            };
+            Schema.prototype.encodeAll = function (useFilters) {
+                return this.encode(true, [], useFilters);
+            };
+            Schema.prototype.applyFilters = function (client, encodeAll) {
+                var _a, _b;
+                if (encodeAll === void 0) { encodeAll = false; }
+                var root = this;
+                var refIdsDissallowed = new Set();
+                var $filterState = ClientState.get(client);
+                var changeTrees = [this.$changes];
+                var numChangeTrees = 1;
+                var filteredBytes = [];
+                var _loop_1 = function (i) {
+                    var changeTree = changeTrees[i];
+                    if (refIdsDissallowed.has(changeTree.refId)) {
+                        return "continue";
+                    }
+                    var ref = changeTree.ref;
+                    var isSchema = ref instanceof Schema;
+                    uint8$1(filteredBytes, SWITCH_TO_STRUCTURE);
+                    number$1(filteredBytes, changeTree.refId);
+                    var clientHasRefId = $filterState.refIds.has(changeTree);
+                    var isEncodeAll = (encodeAll || !clientHasRefId);
+                    // console.log("REF:", ref.constructor.name);
+                    // console.log("Encode all?", isEncodeAll);
+                    //
+                    // include `changeTree` on list of known refIds by this client.
+                    //
+                    $filterState.addRefId(changeTree);
+                    var containerIndexes = $filterState.containerIndexes.get(changeTree);
+                    var changes = (isEncodeAll)
+                        ? Array.from(changeTree.allChanges)
+                        : Array.from(changeTree.changes.values());
+                    //
+                    // WORKAROUND: tries to re-evaluate previously not included @filter() attributes
+                    // - see "DELETE a field of Schema" test case.
+                    //
+                    if (!encodeAll &&
+                        isSchema &&
+                        ref._definition.indexesWithFilters) {
+                        var indexesWithFilters = ref._definition.indexesWithFilters;
+                        indexesWithFilters.forEach(function (indexWithFilter) {
+                            if (!containerIndexes.has(indexWithFilter) &&
+                                changeTree.allChanges.has(indexWithFilter)) {
+                                if (isEncodeAll) {
+                                    changes.push(indexWithFilter);
+                                }
+                                else {
+                                    changes.push({ op: exports.OPERATION.ADD, index: indexWithFilter, });
+                                }
+                            }
+                        });
+                    }
+                    for (var j = 0, cl = changes.length; j < cl; j++) {
+                        var change = (isEncodeAll)
+                            ? { op: exports.OPERATION.ADD, index: changes[j] }
+                            : changes[j];
+                        // custom operations
+                        if (change.op === exports.OPERATION.CLEAR) {
+                            uint8$1(filteredBytes, change.op);
+                            continue;
+                        }
+                        var fieldIndex = change.index;
+                        //
+                        // Deleting fields: encode the operation + field index
+                        //
+                        if (change.op === exports.OPERATION.DELETE) {
+                            //
+                            // DELETE operations also need to go through filtering.
+                            //
+                            // TODO: cache the previous value so we can access the value (primitive or `refId`)
+                            // (check against `$filterState.refIds`)
+                            //
+                            if (isSchema) {
+                                uint8$1(filteredBytes, change.op | fieldIndex);
+                            }
+                            else {
+                                uint8$1(filteredBytes, change.op);
+                                number$1(filteredBytes, fieldIndex);
+                            }
+                            continue;
+                        }
+                        // indexed operation
+                        var value = changeTree.getValue(fieldIndex);
+                        var type = changeTree.getType(fieldIndex);
+                        if (isSchema) {
+                            // Is a Schema!
+                            var filter = (ref._definition.filters &&
+                                ref._definition.filters[fieldIndex]);
+                            if (filter && !filter.call(ref, client, value, root)) {
+                                if (value && value['$changes']) {
+                                    refIdsDissallowed.add(value['$changes'].refId);
+                                }
+                                continue;
+                            }
+                        }
+                        else {
+                            // Is a collection! (map, array, etc.)
+                            var parent = changeTree.parent;
+                            var filter = changeTree.getChildrenFilter();
+                            if (filter && !filter.call(parent, client, ref['$indexes'].get(fieldIndex), value, root)) {
+                                if (value && value['$changes']) {
+                                    refIdsDissallowed.add(value['$changes'].refId);
+                                }
+                                continue;
+                            }
+                        }
+                        // visit child ChangeTree on further iteration.
+                        if (value['$changes']) {
+                            changeTrees.push(value['$changes']);
+                            numChangeTrees++;
+                        }
+                        //
+                        // Copy cached bytes
+                        //
+                        if (change.op !== exports.OPERATION.TOUCH) {
+                            //
+                            // TODO: refactor me!
+                            //
+                            if (change.op === exports.OPERATION.ADD || isSchema) {
+                                //
+                                // use cached bytes directly if is from Schema type.
+                                //
+                                filteredBytes.push.apply(filteredBytes, (_a = changeTree.caches[fieldIndex]) !== null && _a !== void 0 ? _a : []);
+                                containerIndexes.add(fieldIndex);
+                            }
+                            else {
+                                if (containerIndexes.has(fieldIndex)) {
+                                    //
+                                    // use cached bytes if already has the field
+                                    //
+                                    filteredBytes.push.apply(filteredBytes, (_b = changeTree.caches[fieldIndex]) !== null && _b !== void 0 ? _b : []);
+                                }
+                                else {
+                                    //
+                                    // force ADD operation if field is not known by this client.
+                                    //
+                                    containerIndexes.add(fieldIndex);
+                                    uint8$1(filteredBytes, exports.OPERATION.ADD);
+                                    number$1(filteredBytes, fieldIndex);
+                                    if (ref instanceof MapSchema) {
+                                        //
+                                        // MapSchema dynamic key
+                                        //
+                                        var dynamicIndex = changeTree.ref['$indexes'].get(fieldIndex);
+                                        string$1(filteredBytes, dynamicIndex);
+                                    }
+                                    if (value['$changes']) {
+                                        number$1(filteredBytes, value['$changes'].refId);
+                                    }
+                                    else {
+                                        // "encodePrimitiveType" without type checking.
+                                        // the type checking has been done on the first .encode() call.
+                                        encode[type](filteredBytes, value);
+                                    }
+                                }
+                            }
+                        }
+                        else if (value['$changes'] && !isSchema) {
+                            //
+                            // TODO:
+                            // - track ADD/REPLACE/DELETE instances on `$filterState`
+                            // - do NOT always encode dynamicIndex for MapSchema.
+                            //   (If client already has that key, only the first index is necessary.)
+                            //
+                            uint8$1(filteredBytes, exports.OPERATION.ADD);
+                            number$1(filteredBytes, fieldIndex);
+                            if (ref instanceof MapSchema) {
+                                //
+                                // MapSchema dynamic key
+                                //
+                                var dynamicIndex = changeTree.ref['$indexes'].get(fieldIndex);
+                                string$1(filteredBytes, dynamicIndex);
+                            }
+                            number$1(filteredBytes, value['$changes'].refId);
+                        }
+                    }
+                };
+                for (var i = 0; i < numChangeTrees; i++) {
+                    _loop_1(i);
+                }
+                return filteredBytes;
+            };
+            Schema.prototype.clone = function () {
+                var _a;
+                var cloned = new (this.constructor);
+                var schema = this._definition.schema;
+                for (var field in schema) {
+                    if (typeof (this[field]) === "object" &&
+                        typeof ((_a = this[field]) === null || _a === void 0 ? void 0 : _a.clone) === "function") {
+                        // deep clone
+                        cloned[field] = this[field].clone();
+                    }
+                    else {
+                        // primitive values
+                        cloned[field] = this[field];
+                    }
+                }
+                return cloned;
+            };
+            Schema.prototype.toJSON = function () {
+                var schema = this._definition.schema;
+                var deprecated = this._definition.deprecated;
+                var obj = {};
+                for (var field in schema) {
+                    if (!deprecated[field] && this[field] !== null && typeof (this[field]) !== "undefined") {
+                        obj[field] = (typeof (this[field]['toJSON']) === "function")
+                            ? this[field]['toJSON']()
+                            : this["_".concat(field)];
+                    }
+                }
+                return obj;
+            };
+            Schema.prototype.discardAllChanges = function () {
+                this.$changes.discardAll();
+            };
+            Schema.prototype.getByIndex = function (index) {
+                return this[this._definition.fieldsByIndex[index]];
+            };
+            Schema.prototype.deleteByIndex = function (index) {
+                this[this._definition.fieldsByIndex[index]] = undefined;
+            };
+            Schema.prototype.tryEncodeTypeId = function (bytes, type, targetType) {
+                if (type._typeid !== targetType._typeid) {
+                    uint8$1(bytes, TYPE_ID);
+                    number$1(bytes, targetType._typeid);
+                }
+            };
+            Schema.prototype.getSchemaType = function (bytes, it, defaultType) {
+                var type;
+                if (bytes[it.offset] === TYPE_ID) {
+                    it.offset++;
+                    type = this.constructor._context.get(number(bytes, it));
+                }
+                return type || defaultType;
+            };
+            Schema.prototype.createTypeInstance = function (type) {
+                var instance = new type();
+                // assign root on $changes
+                instance.$changes.root = this.$changes.root;
+                return instance;
+            };
+            Schema.prototype._triggerChanges = function (changes) {
+                var _a, _b, _c, _d, _e, _f, _g, _h, _j;
+                var uniqueRefIds = new Set();
+                var $refs = this.$changes.root.refs;
+                var _loop_2 = function (i) {
+                    var change = changes[i];
+                    var refId = change.refId;
+                    var ref = $refs.get(refId);
+                    var $callbacks = ref['$callbacks'];
+                    //
+                    // trigger onRemove on child structure.
+                    //
+                    if ((change.op & exports.OPERATION.DELETE) === exports.OPERATION.DELETE &&
+                        change.previousValue instanceof Schema) {
+                        (_b = (_a = change.previousValue['$callbacks']) === null || _a === void 0 ? void 0 : _a[exports.OPERATION.DELETE]) === null || _b === void 0 ? void 0 : _b.forEach(function (callback) { return callback(); });
+                    }
+                    // no callbacks defined, skip this structure!
+                    if (!$callbacks) {
+                        return "continue";
+                    }
+                    if (ref instanceof Schema) {
+                        if (!uniqueRefIds.has(refId)) {
+                            try {
+                                // trigger onChange
+                                (_c = $callbacks === null || $callbacks === void 0 ? void 0 : $callbacks[exports.OPERATION.REPLACE]) === null || _c === void 0 ? void 0 : _c.forEach(function (callback) {
+                                    return callback(changes);
+                                });
+                            }
+                            catch (e) {
+                                Schema.onError(e);
+                            }
+                        }
+                        try {
+                            if ($callbacks.hasOwnProperty(change.field)) {
+                                (_d = $callbacks[change.field]) === null || _d === void 0 ? void 0 : _d.forEach(function (callback) {
+                                    return callback(change.value, change.previousValue);
+                                });
+                            }
+                        }
+                        catch (e) {
+                            Schema.onError(e);
+                        }
+                    }
+                    else {
+                        // is a collection of items
+                        if (change.op === exports.OPERATION.ADD && change.previousValue === undefined) {
+                            // triger onAdd
+                            (_e = $callbacks[exports.OPERATION.ADD]) === null || _e === void 0 ? void 0 : _e.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
+                        }
+                        else if (change.op === exports.OPERATION.DELETE) {
+                            //
+                            // FIXME: `previousValue` should always be available.
+                            // ADD + DELETE operations are still encoding DELETE operation.
+                            //
+                            if (change.previousValue !== undefined) {
+                                // triger onRemove
+                                (_f = $callbacks[exports.OPERATION.DELETE]) === null || _f === void 0 ? void 0 : _f.forEach(function (callback) { var _a; return callback(change.previousValue, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
+                            }
+                        }
+                        else if (change.op === exports.OPERATION.DELETE_AND_ADD) {
+                            // triger onRemove
+                            if (change.previousValue !== undefined) {
+                                (_g = $callbacks[exports.OPERATION.DELETE]) === null || _g === void 0 ? void 0 : _g.forEach(function (callback) { var _a; return callback(change.previousValue, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
+                            }
+                            // triger onAdd
+                            (_h = $callbacks[exports.OPERATION.ADD]) === null || _h === void 0 ? void 0 : _h.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
+                        }
+                        // trigger onChange
+                        if (change.value !== change.previousValue) {
+                            (_j = $callbacks[exports.OPERATION.REPLACE]) === null || _j === void 0 ? void 0 : _j.forEach(function (callback) { var _a; return callback(change.value, (_a = change.dynamicIndex) !== null && _a !== void 0 ? _a : change.field); });
+                        }
+                    }
+                    uniqueRefIds.add(refId);
+                };
+                for (var i = 0; i < changes.length; i++) {
+                    _loop_2(i);
+                }
+            };
+            Schema._definition = SchemaDefinition.create();
+            return Schema;
+        }());
+
+        function dumpChanges(schema) {
+            var changeTrees = [schema['$changes']];
+            var numChangeTrees = 1;
+            var dump = {};
+            var currentStructure = dump;
+            var _loop_1 = function (i) {
+                var changeTree = changeTrees[i];
+                changeTree.changes.forEach(function (change) {
+                    var ref = changeTree.ref;
+                    var fieldIndex = change.index;
+                    var field = (ref['_definition'])
+                        ? ref['_definition'].fieldsByIndex[fieldIndex]
+                        : ref['$indexes'].get(fieldIndex);
+                    currentStructure[field] = changeTree.getValue(fieldIndex);
+                });
+            };
+            for (var i = 0; i < numChangeTrees; i++) {
+                _loop_1(i);
+            }
+            return dump;
+        }
+
+        var reflectionContext = { context: new Context() };
+        /**
+         * Reflection
+         */
+        var ReflectionField = /** @class */ (function (_super) {
+            __extends(ReflectionField, _super);
+            function ReflectionField() {
+                return _super !== null && _super.apply(this, arguments) || this;
+            }
+            __decorate([
+                type("string", reflectionContext)
+            ], ReflectionField.prototype, "name", void 0);
+            __decorate([
+                type("string", reflectionContext)
+            ], ReflectionField.prototype, "type", void 0);
+            __decorate([
+                type("number", reflectionContext)
+            ], ReflectionField.prototype, "referencedType", void 0);
+            return ReflectionField;
+        }(Schema));
+        var ReflectionType = /** @class */ (function (_super) {
+            __extends(ReflectionType, _super);
+            function ReflectionType() {
+                var _this = _super !== null && _super.apply(this, arguments) || this;
+                _this.fields = new ArraySchema();
+                return _this;
+            }
+            __decorate([
+                type("number", reflectionContext)
+            ], ReflectionType.prototype, "id", void 0);
+            __decorate([
+                type([ReflectionField], reflectionContext)
+            ], ReflectionType.prototype, "fields", void 0);
+            return ReflectionType;
+        }(Schema));
+        var Reflection = /** @class */ (function (_super) {
+            __extends(Reflection, _super);
+            function Reflection() {
+                var _this = _super !== null && _super.apply(this, arguments) || this;
+                _this.types = new ArraySchema();
+                return _this;
+            }
+            Reflection.encode = function (instance) {
+                var rootSchemaType = instance.constructor;
+                var reflection = new Reflection();
+                reflection.rootType = rootSchemaType._typeid;
+                var buildType = function (currentType, schema) {
+                    for (var fieldName in schema) {
+                        var field = new ReflectionField();
+                        field.name = fieldName;
+                        var fieldType = void 0;
+                        if (typeof (schema[fieldName]) === "string") {
+                            fieldType = schema[fieldName];
+                        }
+                        else {
+                            var type_1 = schema[fieldName];
+                            var childTypeSchema = void 0;
+                            //
+                            // TODO: refactor below.
+                            //
+                            if (Schema.is(type_1)) {
+                                fieldType = "ref";
+                                childTypeSchema = schema[fieldName];
+                            }
+                            else {
+                                fieldType = Object.keys(type_1)[0];
+                                if (typeof (type_1[fieldType]) === "string") {
+                                    fieldType += ":" + type_1[fieldType]; // array:string
+                                }
+                                else {
+                                    childTypeSchema = type_1[fieldType];
+                                }
+                            }
+                            field.referencedType = (childTypeSchema)
+                                ? childTypeSchema._typeid
+                                : -1;
+                        }
+                        field.type = fieldType;
+                        currentType.fields.push(field);
+                    }
+                    reflection.types.push(currentType);
+                };
+                var types = rootSchemaType._context.types;
+                for (var typeid in types) {
+                    var type_2 = new ReflectionType();
+                    type_2.id = Number(typeid);
+                    buildType(type_2, types[typeid]._definition.schema);
+                }
+                return reflection.encodeAll();
+            };
+            Reflection.decode = function (bytes, it) {
+                var context = new Context();
+                var reflection = new Reflection();
+                reflection.decode(bytes, it);
+                var schemaTypes = reflection.types.reduce(function (types, reflectionType) {
+                    var schema = /** @class */ (function (_super) {
+                        __extends(_, _super);
+                        function _() {
+                            return _super !== null && _super.apply(this, arguments) || this;
+                        }
+                        return _;
+                    }(Schema));
+                    var typeid = reflectionType.id;
+                    types[typeid] = schema;
+                    context.add(schema, typeid);
+                    return types;
+                }, {});
+                reflection.types.forEach(function (reflectionType) {
+                    var schemaType = schemaTypes[reflectionType.id];
+                    reflectionType.fields.forEach(function (field) {
+                        var _a;
+                        if (field.referencedType !== undefined) {
+                            var fieldType = field.type;
+                            var refType = schemaTypes[field.referencedType];
+                            // map or array of primitive type (-1)
+                            if (!refType) {
+                                var typeInfo = field.type.split(":");
+                                fieldType = typeInfo[0];
+                                refType = typeInfo[1];
+                            }
+                            if (fieldType === "ref") {
+                                type(refType, { context: context })(schemaType.prototype, field.name);
+                            }
+                            else {
+                                type((_a = {}, _a[fieldType] = refType, _a), { context: context })(schemaType.prototype, field.name);
+                            }
+                        }
+                        else {
+                            type(field.type, { context: context })(schemaType.prototype, field.name);
+                        }
+                    });
+                });
+                var rootType = schemaTypes[reflection.rootType];
+                var rootInstance = new rootType();
+                /**
+                 * auto-initialize referenced types on root type
+                 * to allow registering listeners immediatelly on client-side
+                 */
+                for (var fieldName in rootType._definition.schema) {
+                    var fieldType = rootType._definition.schema[fieldName];
+                    if (typeof (fieldType) !== "string") {
+                        rootInstance[fieldName] = (typeof (fieldType) === "function")
+                            ? new fieldType() // is a schema reference
+                            : new (getType(Object.keys(fieldType)[0])).constructor(); // is a "collection"
+                    }
+                }
+                return rootInstance;
+            };
+            __decorate([
+                type([ReflectionType], reflectionContext)
+            ], Reflection.prototype, "types", void 0);
+            __decorate([
+                type("number", reflectionContext)
+            ], Reflection.prototype, "rootType", void 0);
+            return Reflection;
+        }(Schema));
+
+        registerType("map", { constructor: MapSchema });
+        registerType("array", { constructor: ArraySchema });
+        registerType("set", { constructor: SetSchema });
+        registerType("collection", { constructor: CollectionSchema, });
+
+        exports.ArraySchema = ArraySchema;
+        exports.CollectionSchema = CollectionSchema;
+        exports.Context = Context;
+        exports.MapSchema = MapSchema;
+        exports.Reflection = Reflection;
+        exports.ReflectionField = ReflectionField;
+        exports.ReflectionType = ReflectionType;
+        exports.Schema = Schema;
+        exports.SchemaDefinition = SchemaDefinition;
+        exports.SetSchema = SetSchema;
+        exports.decode = decode;
+        exports.defineTypes = defineTypes;
+        exports.deprecated = deprecated;
+        exports.dumpChanges = dumpChanges;
+        exports.encode = encode;
+        exports.filter = filter;
+        exports.filterChildren = filterChildren;
+        exports.hasFilter = hasFilter;
+        exports.registerType = registerType;
+        exports.type = type;
+
+        Object.defineProperty(exports, '__esModule', { value: true });
+
+    }));
+    });
+
+    var Room = /** @class */ (function () {
+        function Room(name, rootSchema) {
+            var _this = this;
+            // Public signals
+            this.onStateChange = createSignal();
+            this.onError = createSignal();
+            this.onLeave = createSignal();
+            this.onJoin = createSignal();
+            this.hasJoined = false;
+            this.onMessageHandlers = createNanoEvents();
+            this.roomId = null;
+            this.name = name;
+            if (rootSchema) {
+                this.serializer = new (getSerializer("schema"));
+                this.rootSchema = rootSchema;
+                this.serializer.state = new rootSchema();
+            }
+            this.onError(function (code, message) { var _a; return (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, "colyseus.js - onError => (".concat(code, ") ").concat(message)); });
+            this.onLeave(function () { return _this.removeAllListeners(); });
+        }
+        Object.defineProperty(Room.prototype, "id", {
+            // TODO: deprecate me on version 1.0
+            get: function () { return this.roomId; },
+            enumerable: false,
+            configurable: true
+        });
+        Room.prototype.connect = function (endpoint, devModeCloseCallback, room // when reconnecting on devMode, re-use previous room intance for handling events.
+        ) {
+            if (room === void 0) { room = this; }
+            var connection = new Connection();
+            room.connection = connection;
+            connection.events.onmessage = Room.prototype.onMessageCallback.bind(room);
+            connection.events.onclose = function (e) {
+                var _a;
+                if (!room.hasJoined) {
+                    (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, "Room connection was closed unexpectedly (".concat(e.code, "): ").concat(e.reason));
+                    room.onError.invoke(e.code, e.reason);
+                    return;
+                }
+                if (e.code === CloseCode.DEVMODE_RESTART && devModeCloseCallback) {
+                    devModeCloseCallback();
+                }
+                else {
+                    room.onLeave.invoke(e.code);
+                    room.destroy();
+                }
+            };
+            connection.events.onerror = function (e) {
+                var _a;
+                (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, "Room, onError (".concat(e.code, "): ").concat(e.reason));
+                room.onError.invoke(e.code, e.reason);
+            };
+            connection.connect(endpoint);
+        };
+        Room.prototype.leave = function (consented) {
+            var _this = this;
+            if (consented === void 0) { consented = true; }
+            return new Promise(function (resolve) {
+                _this.onLeave(function (code) { return resolve(code); });
+                if (_this.connection) {
+                    if (consented) {
+                        _this.connection.send([exports.Protocol.LEAVE_ROOM]);
+                    }
+                    else {
+                        _this.connection.close();
+                    }
+                }
+                else {
+                    _this.onLeave.invoke(CloseCode.CONSENTED);
+                }
+            });
+        };
+        Room.prototype.onMessage = function (type, callback) {
+            return this.onMessageHandlers.on(this.getMessageHandlerKey(type), callback);
+        };
+        Room.prototype.send = function (type, message) {
+            var initialBytes = [exports.Protocol.ROOM_DATA];
+            if (typeof (type) === "string") {
+                umd.encode.string(initialBytes, type);
+            }
+            else {
+                umd.encode.number(initialBytes, type);
+            }
+            var arr;
+            if (message !== undefined) {
+                var encoded = encode(message);
+                arr = new Uint8Array(initialBytes.length + encoded.byteLength);
+                arr.set(new Uint8Array(initialBytes), 0);
+                arr.set(new Uint8Array(encoded), initialBytes.length);
+            }
+            else {
+                arr = new Uint8Array(initialBytes);
+            }
+            this.connection.send(arr.buffer);
+        };
+        Room.prototype.sendBytes = function (type, bytes) {
+            var initialBytes = [exports.Protocol.ROOM_DATA_BYTES];
+            if (typeof (type) === "string") {
+                umd.encode.string(initialBytes, type);
+            }
+            else {
+                umd.encode.number(initialBytes, type);
+            }
+            var arr;
+            arr = new Uint8Array(initialBytes.length + (bytes.byteLength || bytes.length));
+            arr.set(new Uint8Array(initialBytes), 0);
+            arr.set(new Uint8Array(bytes), initialBytes.length);
+            this.connection.send(arr.buffer);
+        };
+        Object.defineProperty(Room.prototype, "state", {
+            get: function () {
+                return this.serializer.getState();
+            },
+            enumerable: false,
+            configurable: true
+        });
+        Room.prototype.removeAllListeners = function () {
+            this.onJoin.clear();
+            this.onStateChange.clear();
+            this.onError.clear();
+            this.onLeave.clear();
+            this.onMessageHandlers.events = {};
+        };
+        Room.prototype.onMessageCallback = function (event) {
+            var bytes = Array.from(new Uint8Array(event.data));
+            var code = bytes[0];
+            if (code === exports.Protocol.JOIN_ROOM) {
+                var offset = 1;
+                var reconnectionToken = utf8Read(bytes, offset);
+                offset += utf8Length(reconnectionToken);
+                this.serializerId = utf8Read(bytes, offset);
+                offset += utf8Length(this.serializerId);
+                // Instantiate serializer if not locally available.
+                if (!this.serializer) {
+                    var serializer = getSerializer(this.serializerId);
+                    this.serializer = new serializer();
+                }
+                if (bytes.length > offset && this.serializer.handshake) {
+                    this.serializer.handshake(bytes, { offset: offset });
+                }
+                this.reconnectionToken = "".concat(this.roomId, ":").concat(reconnectionToken);
+                this.hasJoined = true;
+                this.onJoin.invoke();
+                // acknowledge successfull JOIN_ROOM
+                this.connection.send([exports.Protocol.JOIN_ROOM]);
+            }
+            else if (code === exports.Protocol.ERROR) {
+                var it_1 = { offset: 1 };
+                var code_1 = umd.decode.number(bytes, it_1);
+                var message = umd.decode.string(bytes, it_1);
+                this.onError.invoke(code_1, message);
+            }
+            else if (code === exports.Protocol.LEAVE_ROOM) {
+                this.leave();
+            }
+            else if (code === exports.Protocol.ROOM_DATA_SCHEMA) {
+                var it_2 = { offset: 1 };
+                var context_1 = this.serializer.getState().constructor._context;
+                var type = context_1.get(umd.decode.number(bytes, it_2));
+                var message = new type();
+                message.decode(bytes, it_2);
+                this.dispatchMessage(type, message);
+            }
+            else if (code === exports.Protocol.ROOM_STATE) {
+                bytes.shift(); // drop `code` byte
+                this.setState(bytes);
+            }
+            else if (code === exports.Protocol.ROOM_STATE_PATCH) {
+                bytes.shift(); // drop `code` byte
+                this.patch(bytes);
+            }
+            else if (code === exports.Protocol.ROOM_DATA) {
+                var it_3 = { offset: 1 };
+                var type = (umd.decode.stringCheck(bytes, it_3))
+                    ? umd.decode.string(bytes, it_3)
+                    : umd.decode.number(bytes, it_3);
+                var message = (bytes.length > it_3.offset)
+                    ? decode(event.data, it_3.offset)
+                    : undefined;
+                this.dispatchMessage(type, message);
+            }
+            else if (code === exports.Protocol.ROOM_DATA_BYTES) {
+                var it_4 = { offset: 1 };
+                var type = (umd.decode.stringCheck(bytes, it_4))
+                    ? umd.decode.string(bytes, it_4)
+                    : umd.decode.number(bytes, it_4);
+                this.dispatchMessage(type, new Uint8Array(bytes.slice(it_4.offset)));
+            }
+        };
+        Room.prototype.setState = function (encodedState) {
+            this.serializer.setState(encodedState);
+            this.onStateChange.invoke(this.serializer.getState());
+        };
+        Room.prototype.patch = function (binaryPatch) {
+            this.serializer.patch(binaryPatch);
+            this.onStateChange.invoke(this.serializer.getState());
+        };
+        Room.prototype.dispatchMessage = function (type, message) {
+            var _a;
+            var messageType = this.getMessageHandlerKey(type);
+            if (this.onMessageHandlers.events[messageType]) {
+                this.onMessageHandlers.emit(messageType, message);
+            }
+            else if (this.onMessageHandlers.events['*']) {
+                this.onMessageHandlers.emit('*', type, message);
+            }
+            else {
+                (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, "colyseus.js: onMessage() not registered for type '".concat(type, "'."));
+            }
+        };
+        Room.prototype.destroy = function () {
+            if (this.serializer) {
+                this.serializer.teardown();
+            }
+        };
+        Room.prototype.getMessageHandlerKey = function (type) {
+            switch (typeof (type)) {
+                // typeof Schema
+                case "function": return "$".concat(type._typeid);
+                // string
+                case "string": return type;
+                // number
+                case "number": return "i".concat(type);
+                default: throw new Error("invalid message type.");
+            }
+        };
+        return Room;
+    }());
+
+    function apply(src, tar) {
+    	tar.headers = src.headers || {};
+    	tar.statusMessage = src.statusText;
+    	tar.statusCode = src.status;
+    	tar.data = src.response;
+    }
+
+    function send(method, uri, opts) {
+    	return new Promise(function (res, rej) {
+    		opts = opts || {};
+    		var req = new XMLHttpRequest;
+    		var k, tmp, arr, str=opts.body;
+    		var headers = opts.headers || {};
+
+    		// IE compatible
+    		if (opts.timeout) req.timeout = opts.timeout;
+    		req.ontimeout = req.onerror = function (err) {
+    			err.timeout = err.type == 'timeout';
+    			rej(err);
+    		};
+
+    		req.open(method, uri.href || uri);
+
+    		req.onload = function () {
+    			arr = req.getAllResponseHeaders().trim().split(/[\r\n]+/);
+    			apply(req, req); //=> req.headers
+
+    			while (tmp = arr.shift()) {
+    				tmp = tmp.split(': ');
+    				req.headers[tmp.shift().toLowerCase()] = tmp.join(': ');
+    			}
+
+    			tmp = req.headers['content-type'];
+    			if (tmp && !!~tmp.indexOf('application/json')) {
+    				try {
+    					req.data = JSON.parse(req.data, opts.reviver);
+    				} catch (err) {
+    					apply(req, err);
+    					return rej(err);
+    				}
+    			}
+
+    			(req.status >= 400 ? rej : res)(req);
+    		};
+
+    		if (typeof FormData < 'u' && str instanceof FormData) ; else if (str && typeof str == 'object') {
+    			headers['content-type'] = 'application/json';
+    			str = JSON.stringify(str);
+    		}
+
+    		req.withCredentials = !!opts.withCredentials;
+
+    		for (k in headers) {
+    			req.setRequestHeader(k, headers[k]);
+    		}
+
+    		req.send(str);
+    	});
+    }
+
+    var get = /*#__PURE__*/ send.bind(send, 'GET');
+    var post = /*#__PURE__*/ send.bind(send, 'POST');
+    var patch = /*#__PURE__*/ send.bind(send, 'PATCH');
+    var del = /*#__PURE__*/ send.bind(send, 'DELETE');
+    var put = /*#__PURE__*/ send.bind(send, 'PUT');
+
+    var del_1 = del;
+    var get_1 = get;
+    var patch_1 = patch;
+    var post_1 = post;
+    var put_1 = put;
+    var send_1 = send;
+
+    var xhr = {
+    	del: del_1,
+    	get: get_1,
+    	patch: patch_1,
+    	post: post_1,
+    	put: put_1,
+    	send: send_1
+    };
+
+    var httpie = /*#__PURE__*/_mergeNamespaces({
+        __proto__: null,
+        'default': xhr,
+        del: del_1,
+        get: get_1,
+        patch: patch_1,
+        post: post_1,
+        put: put_1,
+        send: send_1
+    }, [xhr]);
+
+    var HTTP = /** @class */ (function () {
+        function HTTP(client) {
+            this.client = client;
+        }
+        HTTP.prototype.get = function (path, options) {
+            if (options === void 0) { options = {}; }
+            return this.request("get", path, options);
+        };
+        HTTP.prototype.post = function (path, options) {
+            if (options === void 0) { options = {}; }
+            return this.request("post", path, options);
+        };
+        HTTP.prototype.del = function (path, options) {
+            if (options === void 0) { options = {}; }
+            return this.request("del", path, options);
+        };
+        HTTP.prototype.put = function (path, options) {
+            if (options === void 0) { options = {}; }
+            return this.request("put", path, options);
+        };
+        HTTP.prototype.request = function (method, path, options) {
+            if (options === void 0) { options = {}; }
+            return httpie[method](this.client['getHttpEndpoint'](path), this.getOptions(options)).catch(function (e) {
+                var _a;
+                var status = e.statusCode; //  || -1
+                var message = ((_a = e.data) === null || _a === void 0 ? void 0 : _a.error) || e.statusMessage || e.message; //  || "offline"
+                if (!status && !message) {
+                    throw e;
+                }
+                throw new ServerError(status, message);
+            });
+        };
+        HTTP.prototype.getOptions = function (options) {
+            if (this.authToken) {
+                if (!options.headers) {
+                    options.headers = {};
+                }
+                options.headers['Authorization'] = "Bearer ".concat(this.authToken);
+            }
+            if (typeof (cc) !== 'undefined' && cc.sys && cc.sys.isNative) ;
+            else {
+                // always include credentials
+                options.withCredentials = true;
+            }
+            return options;
+        };
+        return HTTP;
+    }());
+
+    /// <reference path="../typings/cocos-creator.d.ts" />
+    /**
+     * We do not assign 'storage' to window.localStorage immediatelly for React
+     * Native compatibility. window.localStorage is not present when this module is
+     * loaded.
+     */
+    var storage;
+    function getStorage() {
+        if (!storage) {
+            try {
+                storage = (typeof (cc) !== 'undefined' && cc.sys && cc.sys.localStorage)
+                    ? cc.sys.localStorage // compatibility with cocos creator
+                    : window.localStorage; // RN does have window object at this point, but localStorage is not defined
+            }
+            catch (e) {
+                // ignore error
+            }
+        }
+        if (!storage) {
+            // mock localStorage if not available (Node.js or RN environment)
+            storage = {
+                cache: {},
+                setItem: function (key, value) { this.cache[key] = value; },
+                getItem: function (key) { this.cache[key]; },
+                removeItem: function (key) { delete this.cache[key]; },
+            };
+        }
+        return storage;
+    }
+    function setItem(key, value) {
+        getStorage().setItem(key, value);
+    }
+    function removeItem(key) {
+        getStorage().removeItem(key);
+    }
+    function getItem(key, callback) {
+        var value = getStorage().getItem(key);
+        if (typeof (Promise) === 'undefined' || // old browsers
+            !(value instanceof Promise)) {
+            // browser has synchronous return
+            callback(value);
+        }
+        else {
+            // react-native is asynchronous
+            value.then(function (id) { return callback(id); });
+        }
+    }
+
+    var _Auth__initialized, _Auth__initializationPromise, _Auth__signInWindow, _Auth__events;
+    var Auth = /** @class */ (function () {
+        function Auth(http) {
+            var _this = this;
+            this.http = http;
+            this.settings = {
+                path: "/auth",
+                key: "colyseus-auth-token",
+            };
+            _Auth__initialized.set(this, false);
+            _Auth__initializationPromise.set(this, void 0);
+            _Auth__signInWindow.set(this, undefined);
+            _Auth__events.set(this, createNanoEvents());
+            getItem(this.settings.key, function (token) { return _this.token = token; });
+        }
+        Object.defineProperty(Auth.prototype, "token", {
+            get: function () {
+                return this.http.authToken;
+            },
+            set: function (token) {
+                this.http.authToken = token;
+            },
+            enumerable: false,
+            configurable: true
+        });
+        Auth.prototype.onChange = function (callback) {
+            var _this = this;
+            var unbindChange = __classPrivateFieldGet(this, _Auth__events, "f").on("change", callback);
+            if (!__classPrivateFieldGet(this, _Auth__initialized, "f")) {
+                __classPrivateFieldSet(this, _Auth__initializationPromise, new Promise(function (resolve, reject) {
+                    _this.getUserData().then(function (userData) {
+                        _this.emitChange(__assign(__assign({}, userData), { token: _this.token }));
+                    }).catch(function (e) {
+                        // user is not logged in, or service is down
+                        _this.emitChange({ user: null, token: undefined });
+                    }).finally(function () {
+                        resolve();
+                    });
+                }), "f");
+            }
+            __classPrivateFieldSet(this, _Auth__initialized, true, "f");
+            return unbindChange;
+        };
+        Auth.prototype.getUserData = function () {
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0:
+                            if (!this.token) return [3 /*break*/, 2];
+                            return [4 /*yield*/, this.http.get("".concat(this.settings.path, "/userdata"))];
+                        case 1: return [2 /*return*/, (_a.sent()).data];
+                        case 2: throw new Error("missing auth.token");
+                    }
+                });
+            });
+        };
+        Auth.prototype.registerWithEmailAndPassword = function (email, password, options) {
+            return __awaiter(this, void 0, void 0, function () {
+                var data;
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.post("".concat(this.settings.path, "/register"), {
+                                body: { email: email, password: password, options: options, },
+                            })];
+                        case 1:
+                            data = (_a.sent()).data;
+                            this.emitChange(data);
+                            return [2 /*return*/, data];
+                    }
+                });
+            });
+        };
+        Auth.prototype.signInWithEmailAndPassword = function (email, password) {
+            return __awaiter(this, void 0, void 0, function () {
+                var data;
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.post("".concat(this.settings.path, "/login"), {
+                                body: { email: email, password: password, },
+                            })];
+                        case 1:
+                            data = (_a.sent()).data;
+                            this.emitChange(data);
+                            return [2 /*return*/, data];
+                    }
+                });
+            });
+        };
+        Auth.prototype.signInAnonymously = function (options) {
+            return __awaiter(this, void 0, void 0, function () {
+                var data;
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.post("".concat(this.settings.path, "/anonymous"), {
+                                body: { options: options, }
+                            })];
+                        case 1:
+                            data = (_a.sent()).data;
+                            this.emitChange(data);
+                            return [2 /*return*/, data];
+                    }
+                });
+            });
+        };
+        Auth.prototype.sendPasswordResetEmail = function (email) {
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.post("".concat(this.settings.path, "/forgot-password"), {
+                                body: { email: email, }
+                            })];
+                        case 1: return [2 /*return*/, (_a.sent()).data];
+                    }
+                });
+            });
+        };
+        Auth.prototype.signInWithProvider = function (providerName, settings) {
+            if (settings === void 0) { settings = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                var _this = this;
+                return __generator(this, function (_a) {
+                    return [2 /*return*/, new Promise(function (resolve, reject) {
+                            var w = settings.width || 480;
+                            var h = settings.height || 768;
+                            // forward existing token for upgrading
+                            var upgradingToken = _this.token ? "?token=".concat(_this.token) : "";
+                            // Capitalize first letter of providerName
+                            var title = "Login with ".concat((providerName[0].toUpperCase() + providerName.substring(1)));
+                            var url = _this.http['client']['getHttpEndpoint']("".concat((settings.prefix || "".concat(_this.settings.path, "/provider")), "/").concat(providerName).concat(upgradingToken));
+                            var left = (screen.width / 2) - (w / 2);
+                            var top = (screen.height / 2) - (h / 2);
+                            __classPrivateFieldSet(_this, _Auth__signInWindow, window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left), "f");
+                            var onMessage = function (event) {
+                                // TODO: it is a good idea to check if event.origin can be trusted!
+                                // if (event.origin.indexOf(window.location.hostname) === -1) { return; }
+                                // require 'user' and 'token' inside received data.
+                                if (event.data.user === undefined && event.data.token === undefined) {
+                                    return;
+                                }
+                                clearInterval(rejectionChecker);
+                                __classPrivateFieldGet(_this, _Auth__signInWindow, "f").close();
+                                __classPrivateFieldSet(_this, _Auth__signInWindow, undefined, "f");
+                                window.removeEventListener("message", onMessage);
+                                if (event.data.error !== undefined) {
+                                    reject(event.data.error);
+                                }
+                                else {
+                                    resolve(event.data);
+                                    _this.emitChange(event.data);
+                                }
+                            };
+                            var rejectionChecker = setInterval(function () {
+                                if (!__classPrivateFieldGet(_this, _Auth__signInWindow, "f") || __classPrivateFieldGet(_this, _Auth__signInWindow, "f").closed) {
+                                    __classPrivateFieldSet(_this, _Auth__signInWindow, undefined, "f");
+                                    reject("cancelled");
+                                    window.removeEventListener("message", onMessage);
+                                }
+                            }, 200);
+                            window.addEventListener("message", onMessage);
+                        })];
+                });
+            });
+        };
+        Auth.prototype.signOut = function () {
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    this.emitChange({ user: null, token: null });
+                    return [2 /*return*/];
+                });
+            });
+        };
+        Auth.prototype.emitChange = function (authData) {
+            if (authData.token !== undefined) {
+                this.token = authData.token;
+                if (authData.token === null) {
+                    removeItem(this.settings.key);
+                }
+                else {
+                    // store key in localStorage
+                    setItem(this.settings.key, authData.token);
+                }
+            }
+            __classPrivateFieldGet(this, _Auth__events, "f").emit("change", authData);
+        };
+        return Auth;
+    }());
+    _Auth__initialized = new WeakMap(), _Auth__initializationPromise = new WeakMap(), _Auth__signInWindow = new WeakMap(), _Auth__events = new WeakMap();
+
+    /**
+     * Discord Embedded App SDK
+     * https://github.com/colyseus/colyseus/issues/707
+     *
+     * All URLs must go through the local proxy from
+     * https://<app_id>.discordsays.com/<backend>/...
+     *
+     * You must configure your URL Mappings with:
+     * - /colyseus/{subdomain} -> {subdomain}.colyseus.cloud
+     *
+     * Example:
+     *  const client = new Client("https://xxxx.colyseus.cloud");
+     *
+     */
+    function discordURLBuilder(url) {
+        var _a;
+        var localHostname = ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname) || "localhost";
+        var remoteHostnameSplitted = url.hostname.split('.');
+        var subdomain = (remoteHostnameSplitted.length > 2)
+            ? "/".concat(remoteHostnameSplitted[0])
+            : '';
+        return "".concat(url.protocol, "//").concat(localHostname, "/colyseus").concat(subdomain).concat(url.pathname).concat(url.search);
+    }
+
+    var _a;
+    var MatchMakeError = /** @class */ (function (_super) {
+        __extends(MatchMakeError, _super);
+        function MatchMakeError(message, code) {
+            var _this = _super.call(this, message) || this;
+            _this.code = code;
+            Object.setPrototypeOf(_this, MatchMakeError.prototype);
+            return _this;
+        }
+        return MatchMakeError;
+    }(Error));
+    // - React Native does not provide `window.location`
+    // - Cocos Creator (Native) does not provide `window.location.hostname`
+    var DEFAULT_ENDPOINT = (typeof (window) !== "undefined" && typeof ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname) !== "undefined")
+        ? "".concat(window.location.protocol.replace("http", "ws"), "//").concat(window.location.hostname).concat((window.location.port && ":".concat(window.location.port)))
+        : "ws://127.0.0.1:2567";
+    var Client = /** @class */ (function () {
+        function Client(settings, customURLBuilder) {
+            if (settings === void 0) { settings = DEFAULT_ENDPOINT; }
+            var _a, _b;
+            if (typeof (settings) === "string") {
+                //
+                // endpoint by url
+                //
+                var url = (settings.startsWith("/"))
+                    ? new URL(settings, DEFAULT_ENDPOINT)
+                    : new URL(settings);
+                var secure = (url.protocol === "https:" || url.protocol === "wss:");
+                var port = Number(url.port || (secure ? 443 : 80));
+                this.settings = {
+                    hostname: url.hostname,
+                    pathname: url.pathname,
+                    port: port,
+                    secure: secure
+                };
+            }
+            else {
+                //
+                // endpoint by settings
+                //
+                if (settings.port === undefined) {
+                    settings.port = (settings.secure) ? 443 : 80;
+                }
+                if (settings.pathname === undefined) {
+                    settings.pathname = "";
+                }
+                this.settings = settings;
+            }
+            // make sure pathname does not end with "/"
+            if (this.settings.pathname.endsWith("/")) {
+                this.settings.pathname = this.settings.pathname.slice(0, -1);
+            }
+            this.http = new HTTP(this);
+            this.auth = new Auth(this.http);
+            this.urlBuilder = customURLBuilder;
+            //
+            // Discord Embedded SDK requires a custom URL builder
+            //
+            if (!this.urlBuilder &&
+                typeof (window) !== "undefined" &&
+                ((_b = (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname) === null || _b === void 0 ? void 0 : _b.includes("discordsays.com"))) {
+                this.urlBuilder = discordURLBuilder;
+                console.log("Colyseus SDK: Discord Embedded SDK detected. Using custom URL builder.");
+            }
+        }
+        Client.prototype.joinOrCreate = function (roomName, options, rootSchema) {
+            if (options === void 0) { options = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.createMatchMakeRequest('joinOrCreate', roomName, options, rootSchema)];
+                        case 1: return [2 /*return*/, _a.sent()];
+                    }
+                });
+            });
+        };
+        Client.prototype.create = function (roomName, options, rootSchema) {
+            if (options === void 0) { options = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.createMatchMakeRequest('create', roomName, options, rootSchema)];
+                        case 1: return [2 /*return*/, _a.sent()];
+                    }
+                });
+            });
+        };
+        Client.prototype.join = function (roomName, options, rootSchema) {
+            if (options === void 0) { options = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.createMatchMakeRequest('join', roomName, options, rootSchema)];
+                        case 1: return [2 /*return*/, _a.sent()];
+                    }
+                });
+            });
+        };
+        Client.prototype.joinById = function (roomId, options, rootSchema) {
+            if (options === void 0) { options = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.createMatchMakeRequest('joinById', roomId, options, rootSchema)];
+                        case 1: return [2 /*return*/, _a.sent()];
+                    }
+                });
+            });
+        };
+        /**
+         * Re-establish connection with a room this client was previously connected to.
+         *
+         * @param reconnectionToken The `room.reconnectionToken` from previously connected room.
+         * @param rootSchema (optional) Concrete root schema definition
+         * @returns Promise<Room>
+         */
+        Client.prototype.reconnect = function (reconnectionToken, rootSchema) {
+            return __awaiter(this, void 0, void 0, function () {
+                var _a, roomId, token;
+                return __generator(this, function (_b) {
+                    switch (_b.label) {
+                        case 0:
+                            if (typeof (reconnectionToken) === "string" && typeof (rootSchema) === "string") {
+                                throw new Error("DEPRECATED: .reconnect() now only accepts 'reconnectionToken' as argument.\nYou can get this token from previously connected `room.reconnectionToken`");
+                            }
+                            _a = reconnectionToken.split(":"), roomId = _a[0], token = _a[1];
+                            if (!roomId || !token) {
+                                throw new Error("Invalid reconnection token format.\nThe format should be roomId:reconnectionToken");
+                            }
+                            return [4 /*yield*/, this.createMatchMakeRequest('reconnect', roomId, { reconnectionToken: token }, rootSchema)];
+                        case 1: return [2 /*return*/, _b.sent()];
+                    }
+                });
+            });
+        };
+        Client.prototype.getAvailableRooms = function (roomName) {
+            if (roomName === void 0) { roomName = ""; }
+            return __awaiter(this, void 0, void 0, function () {
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.get("matchmake/".concat(roomName), {
+                                headers: {
+                                    'Accept': 'application/json'
+                                }
+                            })];
+                        case 1: return [2 /*return*/, (_a.sent()).data];
+                    }
+                });
+            });
+        };
+        Client.prototype.consumeSeatReservation = function (response, rootSchema, reuseRoomInstance // used in devMode
+        ) {
+            return __awaiter(this, void 0, void 0, function () {
+                var room, options, targetRoom;
+                var _this = this;
+                return __generator(this, function (_a) {
+                    room = this.createRoom(response.room.name, rootSchema);
+                    room.roomId = response.room.roomId;
+                    room.sessionId = response.sessionId;
+                    options = { sessionId: room.sessionId };
+                    // forward "reconnection token" in case of reconnection.
+                    if (response.reconnectionToken) {
+                        options.reconnectionToken = response.reconnectionToken;
+                    }
+                    targetRoom = reuseRoomInstance || room;
+                    room.connect(this.buildEndpoint(response.room, options), response.devMode && (function () { return __awaiter(_this, void 0, void 0, function () {
+                        var retryCount, retryMaxRetries, retryReconnection;
+                        var _this = this;
+                        return __generator(this, function (_a) {
+                            console.info("[Colyseus devMode]: ".concat(String.fromCodePoint(0x1F504), " Re-establishing connection with room id '").concat(room.roomId, "'...")); // 🔄
+                            retryCount = 0;
+                            retryMaxRetries = 8;
+                            retryReconnection = function () { return __awaiter(_this, void 0, void 0, function () {
+                                return __generator(this, function (_a) {
+                                    switch (_a.label) {
+                                        case 0:
+                                            retryCount++;
+                                            _a.label = 1;
+                                        case 1:
+                                            _a.trys.push([1, 3, , 4]);
+                                            return [4 /*yield*/, this.consumeSeatReservation(response, rootSchema, targetRoom)];
+                                        case 2:
+                                            _a.sent();
+                                            console.info("[Colyseus devMode]: ".concat(String.fromCodePoint(0x2705), " Successfully re-established connection with room '").concat(room.roomId, "'")); // ✅
+                                            return [3 /*break*/, 4];
+                                        case 3:
+                                            _a.sent();
+                                            if (retryCount < retryMaxRetries) {
+                                                console.info("[Colyseus devMode]: ".concat(String.fromCodePoint(0x1F504), " retrying... (").concat(retryCount, " out of ").concat(retryMaxRetries, ")")); // 🔄
+                                                setTimeout(retryReconnection, 2000);
+                                            }
+                                            else {
+                                                console.info("[Colyseus devMode]: ".concat(String.fromCodePoint(0x274C), " Failed to reconnect. Is your server running? Please check server logs.")); // ❌
+                                            }
+                                            return [3 /*break*/, 4];
+                                        case 4: return [2 /*return*/];
+                                    }
+                                });
+                            }); };
+                            setTimeout(retryReconnection, 2000);
+                            return [2 /*return*/];
+                        });
+                    }); }), targetRoom);
+                    return [2 /*return*/, new Promise(function (resolve, reject) {
+                            var onError = function (code, message) { return reject(new ServerError(code, message)); };
+                            targetRoom.onError.once(onError);
+                            targetRoom['onJoin'].once(function () {
+                                targetRoom.onError.remove(onError);
+                                resolve(targetRoom);
+                            });
+                        })];
+                });
+            });
+        };
+        Client.prototype.createMatchMakeRequest = function (method, roomName, options, rootSchema, reuseRoomInstance) {
+            if (options === void 0) { options = {}; }
+            return __awaiter(this, void 0, void 0, function () {
+                var response;
+                return __generator(this, function (_a) {
+                    switch (_a.label) {
+                        case 0: return [4 /*yield*/, this.http.post("matchmake/".concat(method, "/").concat(roomName), {
+                                headers: {
+                                    'Accept': 'application/json',
+                                    'Content-Type': 'application/json'
+                                },
+                                body: JSON.stringify(options)
+                            })];
+                        case 1:
+                            response = (_a.sent()).data;
+                            // FIXME: HTTP class is already handling this as ServerError.
+                            if (response.error) {
+                                throw new MatchMakeError(response.error, response.code);
+                            }
+                            // forward reconnection token during "reconnect" methods.
+                            if (method === "reconnect") {
+                                response.reconnectionToken = options.reconnectionToken;
+                            }
+                            return [4 /*yield*/, this.consumeSeatReservation(response, rootSchema, reuseRoomInstance)];
+                        case 2: return [2 /*return*/, _a.sent()];
+                    }
+                });
+            });
+        };
+        Client.prototype.createRoom = function (roomName, rootSchema) {
+            return new Room(roomName, rootSchema);
+        };
+        Client.prototype.buildEndpoint = function (room, options) {
+            if (options === void 0) { options = {}; }
+            var params = [];
+            // append provided options
+            for (var name_1 in options) {
+                if (!options.hasOwnProperty(name_1)) {
+                    continue;
+                }
+                params.push("".concat(name_1, "=").concat(options[name_1]));
+            }
+            var endpoint = (this.settings.secure)
+                ? "wss://"
+                : "ws://";
+            if (room.publicAddress) {
+                endpoint += "".concat(room.publicAddress);
+            }
+            else {
+                endpoint += "".concat(this.settings.hostname).concat(this.getEndpointPort()).concat(this.settings.pathname);
+            }
+            var endpointURL = "".concat(endpoint, "/").concat(room.processId, "/").concat(room.roomId, "?").concat(params.join('&'));
+            return (this.urlBuilder)
+                ? this.urlBuilder(new URL(endpointURL))
+                : endpointURL;
+        };
+        Client.prototype.getHttpEndpoint = function (segments) {
+            if (segments === void 0) { segments = ''; }
+            var path = segments.startsWith("/") ? segments : "/".concat(segments);
+            var endpointURL = "".concat((this.settings.secure) ? "https" : "http", "://").concat(this.settings.hostname).concat(this.getEndpointPort()).concat(this.settings.pathname).concat(path);
+            return (this.urlBuilder)
+                ? this.urlBuilder(new URL(endpointURL))
+                : endpointURL;
+        };
+        Client.prototype.getEndpointPort = function () {
+            return (this.settings.port !== 80 && this.settings.port !== 443)
+                ? ":".concat(this.settings.port)
+                : "";
+        };
+        return Client;
+    }());
+
+    var SchemaSerializer = /** @class */ (function () {
+        function SchemaSerializer() {
+        }
+        SchemaSerializer.prototype.setState = function (rawState) {
+            return this.state.decode(rawState);
+        };
+        SchemaSerializer.prototype.getState = function () {
+            return this.state;
+        };
+        SchemaSerializer.prototype.patch = function (patches) {
+            return this.state.decode(patches);
+        };
+        SchemaSerializer.prototype.teardown = function () {
+            var _a, _b;
+            (_b = (_a = this.state) === null || _a === void 0 ? void 0 : _a['$changes']) === null || _b === void 0 ? void 0 : _b.root.clearRefs();
+        };
+        SchemaSerializer.prototype.handshake = function (bytes, it) {
+            if (this.state) {
+                // TODO: validate client/server definitinos
+                var reflection = new umd.Reflection();
+                reflection.decode(bytes, it);
+            }
+            else {
+                // initialize reflected state from server
+                this.state = umd.Reflection.decode(bytes, it);
+            }
+        };
+        return SchemaSerializer;
+    }());
+
+    var NoneSerializer = /** @class */ (function () {
+        function NoneSerializer() {
+        }
+        NoneSerializer.prototype.setState = function (rawState) { };
+        NoneSerializer.prototype.getState = function () { return null; };
+        NoneSerializer.prototype.patch = function (patches) { };
+        NoneSerializer.prototype.teardown = function () { };
+        NoneSerializer.prototype.handshake = function (bytes) { };
+        return NoneSerializer;
+    }());
+
+    registerSerializer('schema', SchemaSerializer);
+    registerSerializer('none', NoneSerializer);
+
+    exports.Auth = Auth;
+    exports.Client = Client;
+    exports.Room = Room;
+    exports.SchemaSerializer = SchemaSerializer;
+    exports.registerSerializer = registerSerializer;
+
+    Object.defineProperty(exports, '__esModule', { value: true });
+
+}));
+//# sourceMappingURL=colyseus-cocos-creator.js.map

+ 17 - 0
assets/colyseus/colyseus-cocos-creator.js.meta

@@ -0,0 +1,17 @@
+{
+  "ver": "4.0.24",
+  "importer": "javascript",
+  "imported": true,
+  "uuid": "a74f9184-247c-4344-a884-42491df8d107",
+  "files": [
+    ".js"
+  ],
+  "subMetas": {},
+  "userData": {
+    "loadPluginInEditor": false,
+    "loadPluginInWeb": true,
+    "loadPluginInNative": true,
+    "loadPluginInMiniGame": true,
+    "isPlugin": true
+  }
+}

+ 774 - 0
assets/colyseus/colyseus.d.ts

@@ -0,0 +1,774 @@
+// Generated by dts-bundle-generator v6.13.0
+
+import * as httpie from 'httpie';
+
+export interface ITransportEventMap {
+	onopen?: ((ev: any) => any) | null;
+	onmessage?: ((ev: any) => any) | null;
+	onclose?: ((ev: any) => any) | null;
+	onerror?: ((ev: any) => any) | null;
+}
+export interface ITransport {
+	isOpen: boolean;
+	send(data: ArrayBuffer | Array<number>): void;
+	connect(url: string): void;
+	close(code?: number, reason?: string): void;
+}
+declare class Connection implements ITransport {
+	transport: ITransport;
+	events: ITransportEventMap;
+	constructor();
+	send(data: ArrayBuffer | Array<number>): void;
+	connect(url: string): void;
+	close(code?: number, reason?: string): void;
+	get isOpen(): boolean;
+}
+export interface Serializer<State> {
+	setState(data: any): void;
+	getState(): State;
+	patch(data: any): void;
+	teardown(): void;
+	handshake?(bytes: number[], it?: any): void;
+}
+export declare function registerSerializer(id: string, serializer: any): void;
+declare enum OPERATION {
+	ADD = 128,
+	REPLACE = 0,
+	DELETE = 64,
+	DELETE_AND_ADD = 192,
+	TOUCH = 1,
+	CLEAR = 10
+}
+/**
+ * Data types
+ */
+export type PrimitiveType = "string" | "number" | "boolean" | "int8" | "uint8" | "int16" | "uint16" | "int32" | "uint32" | "int64" | "uint64" | "float32" | "float64" | typeof Schema;
+export type DefinitionType = PrimitiveType | PrimitiveType[] | {
+	array: PrimitiveType;
+} | {
+	map: PrimitiveType;
+} | {
+	collection: PrimitiveType;
+} | {
+	set: PrimitiveType;
+};
+export type Definition = {
+	[field: string]: DefinitionType;
+};
+export type FilterCallback<T extends Schema = any, V = any, R extends Schema = any> = (((this: T, client: ClientWithSessionId, value: V) => boolean) | ((this: T, client: ClientWithSessionId, value: V, root: R) => boolean));
+export type FilterChildrenCallback<T extends Schema = any, K = any, V = any, R extends Schema = any> = (((this: T, client: ClientWithSessionId, key: K, value: V) => boolean) | ((this: T, client: ClientWithSessionId, key: K, value: V, root: R) => boolean));
+declare class SchemaDefinition {
+	schema: Definition;
+	indexes: {
+		[field: string]: number;
+	};
+	fieldsByIndex: {
+		[index: number]: string;
+	};
+	filters: {
+		[field: string]: FilterCallback;
+	};
+	indexesWithFilters: number[];
+	childFilters: {
+		[field: string]: FilterChildrenCallback;
+	};
+	deprecated: {
+		[field: string]: boolean;
+	};
+	descriptors: PropertyDescriptorMap & ThisType<any>;
+	static create(parent?: SchemaDefinition): SchemaDefinition;
+	addField(field: string, type: DefinitionType): void;
+	hasField(field: string): boolean;
+	addFilter(field: string, cb: FilterCallback): boolean;
+	addChildrenFilter(field: string, cb: FilterChildrenCallback): boolean;
+	getChildrenFilter(field: string): FilterChildrenCallback<any, any, any, any>;
+	getNextFieldIndex(): number;
+}
+export type ClientWithSessionId = {
+	sessionId: string;
+} & any;
+export interface TypeOptions {
+	manual?: boolean;
+	context?: Context;
+}
+declare class Context {
+	types: {
+		[id: number]: typeof Schema;
+	};
+	schemas: Map<typeof Schema, number>;
+	useFilters: boolean;
+	has(schema: typeof Schema): boolean;
+	get(typeid: number): typeof Schema;
+	add(schema: typeof Schema, typeid?: number): void;
+	static create(options?: TypeOptions): (definition: DefinitionType) => PropertyDecorator;
+}
+/**
+ * Copyright (c) 2018 Endel Dreyer
+ * Copyright (c) 2014 Ion Drive Software Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE
+ */
+/**
+ * msgpack implementation highly based on notepack.io
+ * https://github.com/darrachequesne/notepack
+ */
+export interface Iterator {
+	offset: number;
+}
+declare class MapSchema<V = any, K extends string = string> implements Map<K, V>, SchemaDecoderCallbacks {
+	protected $changes: ChangeTree;
+	protected $items: Map<K, V>;
+	protected $indexes: Map<number, K>;
+	protected $refId: number;
+	$callbacks: {
+		[operation: number]: Array<(item: V, key: string) => void>;
+	};
+	onAdd(callback: (item: V, key: string) => void, triggerAll?: boolean): () => boolean;
+	onRemove(callback: (item: V, key: string) => void): () => boolean;
+	onChange(callback: (item: V, key: string) => void): () => boolean;
+	static is(type: any): boolean;
+	constructor(initialValues?: Map<K, V> | Record<K, V>);
+	/** Iterator */
+	[Symbol.iterator](): IterableIterator<[
+		K,
+		V
+	]>;
+	get [Symbol.toStringTag](): string;
+	set(key: K, value: V): this;
+	get(key: K): V | undefined;
+	delete(key: K): boolean;
+	clear(changes?: DataChange[]): void;
+	has(key: K): boolean;
+	forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void): void;
+	entries(): IterableIterator<[
+		K,
+		V
+	]>;
+	keys(): IterableIterator<K>;
+	values(): IterableIterator<V>;
+	get size(): number;
+	protected setIndex(index: number, key: K): void;
+	protected getIndex(index: number): K;
+	protected getByIndex(index: number): V;
+	protected deleteByIndex(index: number): void;
+	toJSON(): any;
+	clone(isDecoding?: boolean): MapSchema<V>;
+}
+declare class ArraySchema<V = any> implements Array<V>, SchemaDecoderCallbacks {
+	protected $changes: ChangeTree;
+	protected $items: Map<number, V>;
+	protected $indexes: Map<number, number>;
+	protected $refId: number;
+	[n: number]: V;
+	$callbacks: {
+		[operation: number]: Array<(item: V, key: number) => void>;
+	};
+	onAdd(callback: (item: V, key: number) => void, triggerAll?: boolean): () => boolean;
+	onRemove(callback: (item: V, key: number) => void): () => boolean;
+	onChange(callback: (item: V, key: number) => void): () => boolean;
+	static is(type: any): boolean;
+	constructor(...items: V[]);
+	set length(value: number);
+	get length(): number;
+	push(...values: V[]): number;
+	/**
+	 * Removes the last element from an array and returns it.
+	 */
+	pop(): V | undefined;
+	at(index: number): V;
+	setAt(index: number, value: V): void;
+	deleteAt(index: number): boolean;
+	protected $deleteAt(index: any): boolean;
+	clear(changes?: DataChange[]): void;
+	/**
+	 * Combines two or more arrays.
+	 * @param items Additional items to add to the end of array1.
+	 */
+	concat(...items: (V | ConcatArray<V>)[]): ArraySchema<V>;
+	/**
+	 * Adds all the elements of an array separated by the specified separator string.
+	 * @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
+	 */
+	join(separator?: string): string;
+	/**
+	 * Reverses the elements in an Array.
+	 */
+	reverse(): ArraySchema<V>;
+	/**
+	 * Removes the first element from an array and returns it.
+	 */
+	shift(): V | undefined;
+	/**
+	 * Returns a section of an array.
+	 * @param start The beginning of the specified portion of the array.
+	 * @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.
+	 */
+	slice(start?: number, end?: number): V[];
+	/**
+	 * Sorts an array.
+	 * @param compareFn Function used to determine the order of the elements. It is expected to return
+	 * a negative value if first argument is less than second argument, zero if they're equal and a positive
+	 * value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.
+	 * ```ts
+	 * [11,2,22,1].sort((a, b) => a - b)
+	 * ```
+	 */
+	sort(compareFn?: (a: V, b: V) => number): this;
+	/**
+	 * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
+	 * @param start The zero-based location in the array from which to start removing elements.
+	 * @param deleteCount The number of elements to remove.
+	 * @param items Elements to insert into the array in place of the deleted elements.
+	 */
+	splice(start: number, deleteCount?: number, ...items: V[]): V[];
+	/**
+	 * Inserts new elements at the start of an array.
+	 * @param items  Elements to insert at the start of the Array.
+	 */
+	unshift(...items: V[]): number;
+	/**
+	 * Returns the index of the first occurrence of a value in an array.
+	 * @param searchElement The value to locate in the array.
+	 * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
+	 */
+	indexOf(searchElement: V, fromIndex?: number): number;
+	/**
+	 * Returns the index of the last occurrence of a specified value in an array.
+	 * @param searchElement The value to locate in the array.
+	 * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at the last index in the array.
+	 */
+	lastIndexOf(searchElement: V, fromIndex?: number): number;
+	/**
+	 * Determines whether all the members of an array satisfy the specified test.
+	 * @param callbackfn A function that accepts up to three arguments. The every method calls
+	 * the callbackfn function for each element in the array until the callbackfn returns a value
+	 * which is coercible to the Boolean value false, or until the end of the array.
+	 * @param thisArg An object to which the this keyword can refer in the callbackfn function.
+	 * If thisArg is omitted, undefined is used as the this value.
+	 */
+	every(callbackfn: (value: V, index: number, array: V[]) => unknown, thisArg?: any): boolean;
+	/**
+	 * Determines whether the specified callback function returns true for any element of an array.
+	 * @param callbackfn A function that accepts up to three arguments. The some method calls
+	 * the callbackfn function for each element in the array until the callbackfn returns a value
+	 * which is coercible to the Boolean value true, or until the end of the array.
+	 * @param thisArg An object to which the this keyword can refer in the callbackfn function.
+	 * If thisArg is omitted, undefined is used as the this value.
+	 */
+	some(callbackfn: (value: V, index: number, array: V[]) => unknown, thisArg?: any): boolean;
+	/**
+	 * Performs the specified action for each element in an array.
+	 * @param callbackfn  A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.
+	 * @param thisArg  An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
+	 */
+	forEach(callbackfn: (value: V, index: number, array: V[]) => void, thisArg?: any): void;
+	/**
+	 * Calls a defined callback function on each element of an array, and returns an array that contains the results.
+	 * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
+	 * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
+	 */
+	map<U>(callbackfn: (value: V, index: number, array: V[]) => U, thisArg?: any): U[];
+	/**
+	 * Returns the elements of an array that meet the condition specified in a callback function.
+	 * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
+	 * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
+	 */
+	filter(callbackfn: (value: V, index: number, array: V[]) => unknown, thisArg?: any): any;
+	/**
+	 * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
+	 * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
+	 * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
+	 */
+	reduce<U = V>(callbackfn: (previousValue: U, currentValue: V, currentIndex: number, array: V[]) => U, initialValue?: U): U;
+	/**
+	 * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
+	 * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array.
+	 * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
+	 */
+	reduceRight<U = V>(callbackfn: (previousValue: U, currentValue: V, currentIndex: number, array: V[]) => U, initialValue?: U): U;
+	/**
+	 * Returns the value of the first element in the array where predicate is true, and undefined
+	 * otherwise.
+	 * @param predicate find calls predicate once for each element of the array, in ascending
+	 * order, until it finds one where predicate returns true. If such an element is found, find
+	 * immediately returns that element value. Otherwise, find returns undefined.
+	 * @param thisArg If provided, it will be used as the this value for each invocation of
+	 * predicate. If it is not provided, undefined is used instead.
+	 */
+	find(predicate: (value: V, index: number, obj: V[]) => boolean, thisArg?: any): V | undefined;
+	/**
+	 * Returns the index of the first element in the array where predicate is true, and -1
+	 * otherwise.
+	 * @param predicate find calls predicate once for each element of the array, in ascending
+	 * order, until it finds one where predicate returns true. If such an element is found,
+	 * findIndex immediately returns that element index. Otherwise, findIndex returns -1.
+	 * @param thisArg If provided, it will be used as the this value for each invocation of
+	 * predicate. If it is not provided, undefined is used instead.
+	 */
+	findIndex(predicate: (value: V, index: number, obj: V[]) => unknown, thisArg?: any): number;
+	/**
+	 * Returns the this object after filling the section identified by start and end with value
+	 * @param value value to fill array section with
+	 * @param start index to start filling the array at. If start is negative, it is treated as
+	 * length+start where length is the length of the array.
+	 * @param end index to stop filling the array at. If end is negative, it is treated as
+	 * length+end.
+	 */
+	fill(value: V, start?: number, end?: number): this;
+	/**
+	 * Returns the this object after copying a section of the array identified by start and end
+	 * to the same array starting at position target
+	 * @param target If target is negative, it is treated as length+target where length is the
+	 * length of the array.
+	 * @param start If start is negative, it is treated as length+start. If end is negative, it
+	 * is treated as length+end.
+	 * @param end If not specified, length of the this object is used as its default value.
+	 */
+	copyWithin(target: number, start: number, end?: number): this;
+	/**
+	 * Returns a string representation of an array.
+	 */
+	toString(): string;
+	/**
+	 * Returns a string representation of an array. The elements are converted to string using their toLocalString methods.
+	 */
+	toLocaleString(): string;
+	/** Iterator */
+	[Symbol.iterator](): IterableIterator<V>;
+	[Symbol.unscopables]: any;
+	/**
+	 * Returns an iterable of key, value pairs for every entry in the array
+	 */
+	entries(): IterableIterator<[
+		number,
+		V
+	]>;
+	/**
+	 * Returns an iterable of keys in the array
+	 */
+	keys(): IterableIterator<number>;
+	/**
+	 * Returns an iterable of values in the array
+	 */
+	values(): IterableIterator<V>;
+	/**
+	 * Determines whether an array includes a certain element, returning true or false as appropriate.
+	 * @param searchElement The element to search for.
+	 * @param fromIndex The position in this array at which to begin searching for searchElement.
+	 */
+	includes(searchElement: V, fromIndex?: number): boolean;
+	/**
+	 * Calls a defined callback function on each element of an array. Then, flattens the result into
+	 * a new array.
+	 * This is identical to a map followed by flat with depth 1.
+	 *
+	 * @param callback A function that accepts up to three arguments. The flatMap method calls the
+	 * callback function one time for each element in the array.
+	 * @param thisArg An object to which the this keyword can refer in the callback function. If
+	 * thisArg is omitted, undefined is used as the this value.
+	 */
+	flatMap<U, This = undefined>(callback: (this: This, value: V, index: number, array: V[]) => U | ReadonlyArray<U>, thisArg?: This): U[];
+	/**
+	 * Returns a new array with all sub-array elements concatenated into it recursively up to the
+	 * specified depth.
+	 *
+	 * @param depth The maximum recursion depth
+	 */
+	flat<A, D extends number = 1>(this: A, depth?: D): any;
+	findLast(): any;
+	findLastIndex(...args: any[]): any;
+	protected setIndex(index: number, key: number): void;
+	protected getIndex(index: number): number;
+	protected getByIndex(index: number): V;
+	protected deleteByIndex(index: number): void;
+	toArray(): V[];
+	toJSON(): any[];
+	clone(isDecoding?: boolean): ArraySchema<V>;
+}
+export type K = number;
+declare class CollectionSchema<V = any> implements SchemaDecoderCallbacks {
+	protected $changes: ChangeTree;
+	protected $items: Map<number, V>;
+	protected $indexes: Map<number, number>;
+	protected $refId: number;
+	$callbacks: {
+		[operation: number]: Array<(item: V, key: string) => void>;
+	};
+	onAdd(callback: (item: V, key: string) => void, triggerAll?: boolean): () => boolean;
+	onRemove(callback: (item: V, key: string) => void): () => boolean;
+	onChange(callback: (item: V, key: string) => void): () => boolean;
+	static is(type: any): boolean;
+	constructor(initialValues?: Array<V>);
+	add(value: V): number;
+	at(index: number): V | undefined;
+	entries(): IterableIterator<[
+		number,
+		V
+	]>;
+	delete(item: V): boolean;
+	clear(changes?: DataChange[]): void;
+	has(value: V): boolean;
+	forEach(callbackfn: (value: V, key: K, collection: CollectionSchema<V>) => void): void;
+	values(): IterableIterator<V>;
+	get size(): number;
+	protected setIndex(index: number, key: number): void;
+	protected getIndex(index: number): number;
+	protected getByIndex(index: number): V;
+	protected deleteByIndex(index: number): void;
+	toArray(): V[];
+	toJSON(): V[];
+	clone(isDecoding?: boolean): CollectionSchema<V>;
+}
+declare class SetSchema<V = any> implements SchemaDecoderCallbacks {
+	protected $changes: ChangeTree;
+	protected $items: Map<number, V>;
+	protected $indexes: Map<number, number>;
+	protected $refId: number;
+	$callbacks: {
+		[operation: number]: Array<(item: V, key: string) => void>;
+	};
+	onAdd(callback: (item: V, key: string) => void, triggerAll?: boolean): () => boolean;
+	onRemove(callback: (item: V, key: string) => void): () => boolean;
+	onChange(callback: (item: V, key: string) => void): () => boolean;
+	static is(type: any): boolean;
+	constructor(initialValues?: Array<V>);
+	add(value: V): number | false;
+	entries(): IterableIterator<[
+		number,
+		V
+	]>;
+	delete(item: V): boolean;
+	clear(changes?: DataChange[]): void;
+	has(value: V): boolean;
+	forEach(callbackfn: (value: V, key: number, collection: SetSchema<V>) => void): void;
+	values(): IterableIterator<V>;
+	get size(): number;
+	protected setIndex(index: number, key: number): void;
+	protected getIndex(index: number): number;
+	protected getByIndex(index: number): V;
+	protected deleteByIndex(index: number): void;
+	toArray(): V[];
+	toJSON(): V[];
+	clone(isDecoding?: boolean): SetSchema<V>;
+}
+declare class ReferenceTracker {
+	refs: Map<number, Ref>;
+	refCounts: {
+		[refId: number]: number;
+	};
+	deletedRefs: Set<number>;
+	protected nextUniqueId: number;
+	getNextUniqueId(): number;
+	addRef(refId: number, ref: Ref, incrementCount?: boolean): void;
+	removeRef(refId: any): void;
+	clearRefs(): void;
+	garbageCollectDeletedRefs(): void;
+}
+export type Ref = Schema | ArraySchema | MapSchema | CollectionSchema | SetSchema;
+export interface ChangeOperation {
+	op: OPERATION;
+	index: number;
+}
+declare class ChangeTree {
+	ref: Ref;
+	refId: number;
+	root?: ReferenceTracker;
+	parent?: Ref;
+	parentIndex?: number;
+	indexes: {
+		[index: string]: any;
+	};
+	changed: boolean;
+	changes: Map<number, ChangeOperation>;
+	allChanges: Set<number>;
+	caches: {
+		[field: number]: number[];
+	};
+	currentCustomOperation: number;
+	constructor(ref: Ref, parent?: Ref, root?: ReferenceTracker);
+	setParent(parent: Ref, root?: ReferenceTracker, parentIndex?: number): void;
+	operation(op: ChangeOperation): void;
+	change(fieldName: string | number, operation?: OPERATION): void;
+	touch(fieldName: string | number): void;
+	touchParents(): void;
+	getType(index?: number): any;
+	getChildrenFilter(): FilterChildrenCallback;
+	getValue(index: number): any;
+	delete(fieldName: string | number): void;
+	discard(changed?: boolean, discardAll?: boolean): void;
+	/**
+	 * Recursively discard all changes from this, and child structures.
+	 */
+	discardAll(): void;
+	cache(field: number, cachedBytes: number[]): void;
+	clone(): ChangeTree;
+	ensureRefId(): void;
+	protected assertValidIndex(index: number, fieldName: string | number): void;
+}
+export type NonFunctionPropNames<T> = {
+	[K in keyof T]: T[K] extends Function ? never : K;
+}[keyof T];
+export interface DataChange<T = any, F = string> {
+	refId: number;
+	op: OPERATION;
+	field: F;
+	dynamicIndex?: number | string;
+	value: T;
+	previousValue: T;
+}
+export interface SchemaDecoderCallbacks<TValue = any, TKey = any> {
+	$callbacks: {
+		[operation: number]: Array<(item: TValue, key: TKey) => void>;
+	};
+	onAdd(callback: (item: any, key: any) => void, ignoreExisting?: boolean): () => void;
+	onRemove(callback: (item: any, key: any) => void): () => void;
+	onChange(callback: (item: any, key: any) => void): () => void;
+	clone(decoding?: boolean): SchemaDecoderCallbacks;
+	clear(changes?: DataChange[]): any;
+	decode?(byte: any, it: Iterator): any;
+}
+declare abstract class Schema {
+	static _typeid: number;
+	static _context: Context;
+	static _definition: SchemaDefinition;
+	static onError(e: any): void;
+	static is(type: DefinitionType): boolean;
+	protected $changes: ChangeTree;
+	protected $callbacks: {
+		[op: number]: Array<Function>;
+	};
+	onChange(callback: (changes: DataChange[]) => void): () => void;
+	onRemove(callback: () => void): () => void;
+	constructor(...args: any[]);
+	assign(props: {
+		[prop in NonFunctionPropNames<this>]?: this[prop];
+	}): this;
+	protected get _definition(): SchemaDefinition;
+	/**
+	 * (Server-side): Flag a property to be encoded for the next patch.
+	 * @param instance Schema instance
+	 * @param property string representing the property name, or number representing the index of the property.
+	 * @param operation OPERATION to perform (detected automatically)
+	 */
+	setDirty<K extends NonFunctionPropNames<this>>(property: K | number, operation?: OPERATION): void;
+	/**
+	 * Client-side: listen for changes on property.
+	 * @param prop the property name
+	 * @param callback callback to be triggered on property change
+	 * @param immediate trigger immediatelly if property has been already set.
+	 */
+	listen<K extends NonFunctionPropNames<this>>(prop: K, callback: (value: this[K], previousValue: this[K]) => void, immediate?: boolean): () => boolean;
+	decode(bytes: number[], it?: Iterator, ref?: Ref): DataChange<any, string>[];
+	encode(encodeAll?: boolean, bytes?: number[], useFilters?: boolean): number[];
+	encodeAll(useFilters?: boolean): number[];
+	applyFilters(client: ClientWithSessionId, encodeAll?: boolean): number[];
+	clone(): this;
+	toJSON(): {};
+	discardAllChanges(): void;
+	protected getByIndex(index: number): any;
+	protected deleteByIndex(index: number): void;
+	private tryEncodeTypeId;
+	private getSchemaType;
+	private createTypeInstance;
+	private _triggerChanges;
+}
+export type SchemaConstructor<T = Schema> = new (...args: any[]) => T;
+export declare class SchemaSerializer<T extends Schema = any> implements Serializer<T> {
+	state: T;
+	setState(rawState: any): import("@colyseus/schema").DataChange<any, string>[];
+	getState(): T;
+	patch(patches: any): import("@colyseus/schema").DataChange<any, string>[];
+	teardown(): void;
+	handshake(bytes: number[], it?: Iterator): void;
+}
+export type FunctionParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
+declare class EventEmitter<CallbackSignature extends (...args: any[]) => any> {
+	handlers: Array<CallbackSignature>;
+	register(cb: CallbackSignature, once?: boolean): this;
+	invoke(...args: FunctionParameters<CallbackSignature>): void;
+	invokeAsync(...args: FunctionParameters<CallbackSignature>): Promise<any[]>;
+	remove(cb: CallbackSignature): void;
+	clear(): void;
+}
+export interface RoomAvailable<Metadata = any> {
+	name: string;
+	roomId: string;
+	clients: number;
+	maxClients: number;
+	metadata?: Metadata;
+}
+export declare class Room<State = any> {
+	roomId: string;
+	sessionId: string;
+	reconnectionToken: string;
+	name: string;
+	connection: Connection;
+	onStateChange: {
+		once: (cb: (state: State) => void) => void;
+		remove: (cb: (state: State) => void) => void;
+		invoke: (state: State) => void;
+		invokeAsync: (state: State) => Promise<any[]>;
+		clear: () => void;
+	} & ((this: any, cb: (state: State) => void) => EventEmitter<(state: State) => void>);
+	onError: {
+		once: (cb: (code: number, message?: string) => void) => void;
+		remove: (cb: (code: number, message?: string) => void) => void;
+		invoke: (code: number, message?: string) => void;
+		invokeAsync: (code: number, message?: string) => Promise<any[]>;
+		clear: () => void;
+	} & ((this: any, cb: (code: number, message?: string) => void) => EventEmitter<(code: number, message?: string) => void>);
+	onLeave: {
+		once: (cb: (code: number) => void) => void;
+		remove: (cb: (code: number) => void) => void;
+		invoke: (code: number) => void;
+		invokeAsync: (code: number) => Promise<any[]>;
+		clear: () => void;
+	} & ((this: any, cb: (code: number) => void) => EventEmitter<(code: number) => void>);
+	protected onJoin: {
+		once: (cb: (...args: any[]) => void | Promise<any>) => void;
+		remove: (cb: (...args: any[]) => void | Promise<any>) => void;
+		invoke: (...args: any[]) => void;
+		invokeAsync: (...args: any[]) => Promise<any[]>;
+		clear: () => void;
+	} & ((this: any, cb: (...args: any[]) => void | Promise<any>) => EventEmitter<(...args: any[]) => void | Promise<any>>);
+	serializerId: string;
+	serializer: Serializer<State>;
+	protected hasJoined: boolean;
+	protected rootSchema: SchemaConstructor<State>;
+	protected onMessageHandlers: {
+		emit(event: string, ...args: any[]): void;
+		events: {};
+		on(event: string, cb: (...args: any[]) => void): () => void;
+	};
+	constructor(name: string, rootSchema?: SchemaConstructor<State>);
+	get id(): string;
+	connect(endpoint: string, devModeCloseCallback?: () => void, room?: Room): void;
+	leave(consented?: boolean): Promise<number>;
+	onMessage<T = any>(type: "*", callback: (type: string | number | Schema, message: T) => void): any;
+	onMessage<T extends (typeof Schema & (new (...args: any[]) => any))>(type: T, callback: (message: InstanceType<T>) => void): any;
+	onMessage<T = any>(type: string | number, callback: (message: T) => void): any;
+	send<T = any>(type: string | number, message?: T): void;
+	sendBytes(type: string | number, bytes: number[] | ArrayBufferLike): void;
+	get state(): State;
+	removeAllListeners(): void;
+	protected onMessageCallback(event: MessageEvent): void;
+	protected setState(encodedState: number[]): void;
+	protected patch(binaryPatch: number[]): void;
+	private dispatchMessage;
+	private destroy;
+	private getMessageHandlerKey;
+}
+declare class HTTP {
+	protected client: Client;
+	authToken: string;
+	constructor(client: Client);
+	get<T = any>(path: string, options?: Partial<httpie.Options>): Promise<httpie.Response<T>>;
+	post<T = any>(path: string, options?: Partial<httpie.Options>): Promise<httpie.Response<T>>;
+	del<T = any>(path: string, options?: Partial<httpie.Options>): Promise<httpie.Response<T>>;
+	put<T = any>(path: string, options?: Partial<httpie.Options>): Promise<httpie.Response<T>>;
+	protected request(method: "get" | "post" | "put" | "del", path: string, options?: Partial<httpie.Options>): Promise<httpie.Response>;
+	protected getOptions(options: Partial<httpie.Options>): Partial<httpie.Options>;
+}
+export interface AuthSettings {
+	path: string;
+	key: string;
+}
+export interface PopupSettings {
+	prefix: string;
+	width: number;
+	height: number;
+}
+export interface AuthData {
+	user: any;
+	token: string;
+}
+export declare class Auth {
+	#private;
+	protected http: HTTP;
+	settings: AuthSettings;
+	constructor(http: HTTP);
+	set token(token: string);
+	get token(): string;
+	onChange(callback: (response: AuthData) => void): () => void;
+	getUserData(): Promise<any>;
+	registerWithEmailAndPassword(email: string, password: string, options?: any): Promise<any>;
+	signInWithEmailAndPassword(email: string, password: string): Promise<any>;
+	signInAnonymously(options?: any): Promise<any>;
+	sendPasswordResetEmail(email: string): Promise<any>;
+	signInWithProvider(providerName: string, settings?: Partial<PopupSettings>): Promise<unknown>;
+	signOut(): Promise<void>;
+	private emitChange;
+}
+export type JoinOptions = any;
+export interface EndpointSettings {
+	hostname: string;
+	secure: boolean;
+	port?: number;
+	pathname?: string;
+}
+export declare class Client {
+	http: HTTP;
+	auth: Auth;
+	protected settings: EndpointSettings;
+	protected urlBuilder: (url: URL) => string;
+	constructor(settings?: string | EndpointSettings, customURLBuilder?: (url: URL) => string);
+	joinOrCreate<T>(roomName: string, options?: JoinOptions, rootSchema?: SchemaConstructor<T>): Promise<Room<T>>;
+	create<T>(roomName: string, options?: JoinOptions, rootSchema?: SchemaConstructor<T>): Promise<Room<T>>;
+	join<T>(roomName: string, options?: JoinOptions, rootSchema?: SchemaConstructor<T>): Promise<Room<T>>;
+	joinById<T>(roomId: string, options?: JoinOptions, rootSchema?: SchemaConstructor<T>): Promise<Room<T>>;
+	/**
+	 * Re-establish connection with a room this client was previously connected to.
+	 *
+	 * @param reconnectionToken The `room.reconnectionToken` from previously connected room.
+	 * @param rootSchema (optional) Concrete root schema definition
+	 * @returns Promise<Room>
+	 */
+	reconnect<T>(reconnectionToken: string, rootSchema?: SchemaConstructor<T>): Promise<Room<T>>;
+	getAvailableRooms<Metadata = any>(roomName?: string): Promise<RoomAvailable<Metadata>[]>;
+	consumeSeatReservation<T>(response: any, rootSchema?: SchemaConstructor<T>, reuseRoomInstance?: Room): Promise<Room<T>>;
+	protected createMatchMakeRequest<T>(method: string, roomName: string, options?: JoinOptions, rootSchema?: SchemaConstructor<T>, reuseRoomInstance?: Room): Promise<Room<T>>;
+	protected createRoom<T>(roomName: string, rootSchema?: SchemaConstructor<T>): Room<T>;
+	protected buildEndpoint(room: any, options?: any): string;
+	protected getHttpEndpoint(segments?: string): string;
+	protected getEndpointPort(): string;
+}
+export declare enum Protocol {
+	HANDSHAKE = 9,
+	JOIN_ROOM = 10,
+	ERROR = 11,
+	LEAVE_ROOM = 12,
+	ROOM_DATA = 13,
+	ROOM_STATE = 14,
+	ROOM_STATE_PATCH = 15,
+	ROOM_DATA_SCHEMA = 16,
+	ROOM_DATA_BYTES = 17
+}
+export declare enum ErrorCode {
+	MATCHMAKE_NO_HANDLER = 4210,
+	MATCHMAKE_INVALID_CRITERIA = 4211,
+	MATCHMAKE_INVALID_ROOM_ID = 4212,
+	MATCHMAKE_UNHANDLED = 4213,
+	MATCHMAKE_EXPIRED = 4214,
+	AUTH_FAILED = 4215,
+	APPLICATION_ERROR = 4216
+}
+
+export as namespace Colyseus;
+
+export {};

+ 9 - 0
assets/colyseus/colyseus.d.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "bff59442-5892-4bfa-a025-f97c9e5bf8e4",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 11 - 0
assets/lobbyRes.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "a123cb9d-696c-4805-b613-edf772dd53b0",
+  "files": [],
+  "subMetas": {},
+  "userData": {
+    "isBundle": true
+  }
+}

+ 9 - 0
assets/lobbyRes/scenes.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "6a06fd9c-21b8-44a3-9de9-e21e679a071d",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 795 - 0
assets/lobbyRes/scenes/Game.scene

@@ -0,0 +1,795 @@
+[
+  {
+    "__type__": "cc.SceneAsset",
+    "_name": "Game",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "scene": {
+      "__id__": 1
+    }
+  },
+  {
+    "__type__": "cc.Scene",
+    "_name": "Game",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 4
+      }
+    ],
+    "_active": true,
+    "_components": [],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "autoReleaseAssets": false,
+    "_globals": {
+      "__id__": 18
+    },
+    "_id": "839abcee-b5fb-49c7-89d4-1b186bd76846"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Camera",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 640,
+      "y": 360,
+      "z": 1000
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "cdkqXp7q1D/K4Np7kNq5aa"
+  },
+  {
+    "__type__": "cc.Camera",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_projection": 0,
+    "_priority": 0,
+    "_fov": 45,
+    "_fovAxis": 0,
+    "_orthoHeight": 360,
+    "_near": 1,
+    "_far": 2000,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 51,
+      "g": 51,
+      "b": 51,
+      "a": 255
+    },
+    "_depth": 1,
+    "_stencil": 0,
+    "_clearFlags": 7,
+    "_rect": {
+      "__type__": "cc.Rect",
+      "x": 0,
+      "y": 0,
+      "width": 1,
+      "height": 1
+    },
+    "_aperture": 19,
+    "_shutter": 7,
+    "_iso": 0,
+    "_screenScale": 1,
+    "_visibility": 1117782015,
+    "_targetTexture": null,
+    "_postProcess": null,
+    "_usePostProcess": false,
+    "_cameraType": -1,
+    "_trackingType": 0,
+    "_id": "edaMqHEOlJuLpuzpX5oQPC"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Canvas",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [
+      {
+        "__id__": 5
+      },
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 12
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 15
+      },
+      {
+        "__id__": 16
+      },
+      {
+        "__id__": 17
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 640,
+      "y": 360,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "aexK3+1PhKupVBYHDg9c0I"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "GameController",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 6
+      },
+      {
+        "__id__": 7
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "25wV0WQgdH0bX/wOGPI1e6"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "1azVX2FilK2Y9Fpp/Pyr9E"
+  },
+  {
+    "__type__": "8f7122oJzNKarXjQaGGn0Ks",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "webView": {
+      "__id__": 8
+    },
+    "loadingNode": {
+      "__id__": 12
+    },
+    "_id": "598ZALtjZEiILvMLNoyai2"
+  },
+  {
+    "__type__": "cc.WebView",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 9
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_url": "",
+    "webviewEvents": [],
+    "_id": "ceuikq91tPvYAm1akCQ7NP"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "GameWebView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 10
+      },
+      {
+        "__id__": 11
+      },
+      {
+        "__id__": 8
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "93k8A5MtdCC6GoPlNzCcs6"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 9
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "00wTVczJlDdZh/+tuzvv3+"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 9
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 1280,
+    "_originalHeight": 720,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "5ehHXVQnpGEZrAu/TPXI/+"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "GameLoading",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 13
+      },
+      {
+        "__id__": 14
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "13CjXjjbhBYbmKC/AVS1dB"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 12
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 186.671875,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "acycTC109FyYKHEIJ6RRer"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 12
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_string": "游戏加载中...",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 32,
+    "_fontSize": 32,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": "19YTPdxRdLcIbnJOZgjn5q"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "fakrWHPhFDXodBU8Y77FQk"
+  },
+  {
+    "__type__": "cc.Canvas",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_cameraComponent": {
+      "__id__": 3
+    },
+    "_alignCanvasWithScreen": true,
+    "_id": "0eHFgL/hlLs5JfQSO9a5mA"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 1280,
+    "_originalHeight": 720,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "9atJkhfUtOzp5VWR56Al7P"
+  },
+  {
+    "__type__": "cc.SceneGlobals",
+    "ambient": {
+      "__id__": 19
+    },
+    "shadows": {
+      "__id__": 20
+    },
+    "_skybox": {
+      "__id__": 21
+    },
+    "fog": {
+      "__id__": 22
+    },
+    "octree": {
+      "__id__": 23
+    },
+    "skin": {
+      "__id__": 24
+    },
+    "lightProbeInfo": {
+      "__id__": 25
+    },
+    "postSettings": {
+      "__id__": 26
+    },
+    "bakedWithStationaryMainLight": false,
+    "bakedWithHighpLightmap": false
+  },
+  {
+    "__type__": "cc.AmbientInfo",
+    "_skyColorHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyColor": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyIllumHDR": 20000,
+    "_skyIllum": 20000,
+    "_groundAlbedoHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_groundAlbedo": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_skyColorLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 1
+    },
+    "_skyIllumLDR": 20000,
+    "_groundAlbedoLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "cc.ShadowsInfo",
+    "_enabled": false,
+    "_type": 0,
+    "_normal": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 1,
+      "z": 0
+    },
+    "_distance": 0,
+    "_planeBias": 1,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 76
+    },
+    "_maxReceived": 4,
+    "_size": {
+      "__type__": "cc.Vec2",
+      "x": 1024,
+      "y": 1024
+    }
+  },
+  {
+    "__type__": "cc.SkyboxInfo",
+    "_envLightingType": 0,
+    "_envmapHDR": null,
+    "_envmap": null,
+    "_envmapLDR": null,
+    "_diffuseMapHDR": null,
+    "_diffuseMapLDR": null,
+    "_enabled": false,
+    "_useHDR": true,
+    "_editableMaterial": null,
+    "_reflectionHDR": null,
+    "_reflectionLDR": null,
+    "_rotationAngle": 0
+  },
+  {
+    "__type__": "cc.FogInfo",
+    "_type": 0,
+    "_fogColor": {
+      "__type__": "cc.Color",
+      "r": 200,
+      "g": 200,
+      "b": 200,
+      "a": 255
+    },
+    "_enabled": false,
+    "_fogDensity": 0.3,
+    "_fogStart": 0.5,
+    "_fogEnd": 300,
+    "_fogAtten": 5,
+    "_fogTop": 1.5,
+    "_fogRange": 1.2,
+    "_accurate": false
+  },
+  {
+    "__type__": "cc.OctreeInfo",
+    "_enabled": false,
+    "_minPos": {
+      "__type__": "cc.Vec3",
+      "x": -1024,
+      "y": -1024,
+      "z": -1024
+    },
+    "_maxPos": {
+      "__type__": "cc.Vec3",
+      "x": 1024,
+      "y": 1024,
+      "z": 1024
+    },
+    "_depth": 8
+  },
+  {
+    "__type__": "cc.SkinInfo",
+    "_enabled": true,
+    "_blurRadius": 0.01,
+    "_sssIntensity": 3
+  },
+  {
+    "__type__": "cc.LightProbeInfo",
+    "_giScale": 1,
+    "_giSamples": 1024,
+    "_bounces": 2,
+    "_reduceRinging": 0,
+    "_showProbe": true,
+    "_showWireframe": true,
+    "_showConvex": false,
+    "_data": null,
+    "_lightProbeSphereVolume": 1
+  },
+  {
+    "__type__": "cc.PostSettingsInfo",
+    "_toneMappingType": 0
+  }
+]

+ 11 - 0
assets/lobbyRes/scenes/Game.scene.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.1.50",
+  "importer": "scene",
+  "imported": true,
+  "uuid": "839abcee-b5fb-49c7-89d4-1b186bd76846",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 1518 - 0
assets/lobbyRes/scenes/Lobby.scene

@@ -0,0 +1,1518 @@
+[
+  {
+    "__type__": "cc.SceneAsset",
+    "_name": "Lobby",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "scene": {
+      "__id__": 1
+    }
+  },
+  {
+    "__type__": "cc.Scene",
+    "_name": "Lobby",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 4
+      }
+    ],
+    "_active": true,
+    "_components": [],
+    "_prefab": {
+      "__id__": 51
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "autoReleaseAssets": false,
+    "_globals": {
+      "__id__": 54
+    },
+    "_id": "4a86fbd9-0bb0-4388-8633-ac16da3f4e5e"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Camera",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 667,
+      "y": 374.99999999999994,
+      "z": 1000
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "e3rW7WnJpOZYUTiKlXF5qm"
+  },
+  {
+    "__type__": "cc.Camera",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_projection": 0,
+    "_priority": 0,
+    "_fov": 45,
+    "_fovAxis": 0,
+    "_orthoHeight": 416.5695970695971,
+    "_near": 1,
+    "_far": 2000,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 51,
+      "g": 51,
+      "b": 51,
+      "a": 255
+    },
+    "_depth": 1,
+    "_stencil": 0,
+    "_clearFlags": 7,
+    "_rect": {
+      "__type__": "cc.Rect",
+      "x": 0,
+      "y": 0,
+      "width": 1,
+      "height": 1
+    },
+    "_aperture": 19,
+    "_shutter": 7,
+    "_iso": 0,
+    "_screenScale": 1,
+    "_visibility": 1117782015,
+    "_targetTexture": null,
+    "_postProcess": null,
+    "_usePostProcess": false,
+    "_cameraType": -1,
+    "_trackingType": 0,
+    "_id": "cbUGjKh1BEu70DxObuYwjL"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Canvas",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [
+      {
+        "__id__": 5
+      },
+      {
+        "__id__": 8
+      },
+      {
+        "__id__": 21
+      },
+      {
+        "__id__": 24
+      },
+      {
+        "__id__": 27
+      },
+      {
+        "__id__": 30
+      },
+      {
+        "__id__": 45
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 48
+      },
+      {
+        "__id__": 49
+      },
+      {
+        "__id__": 50
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 667,
+      "y": 374.99999999999994,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "dc12eCX0NBRar7G1KzeaL4"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "LobbyController",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 6
+      },
+      {
+        "__id__": 7
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "c9TRyr8aJNC76KznjcAYUH"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "3eDnQHLXJI+Z9FNV9osPw+"
+  },
+  {
+    "__type__": "2b3d6KDLMpAXpHY4C90MJdv",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "pageLayer": {
+      "__id__": 8
+    },
+    "windowLayer": {
+      "__id__": 21
+    },
+    "popupLayer": {
+      "__id__": 24
+    },
+    "toastLayer": {
+      "__id__": 27
+    },
+    "loadingLayer": {
+      "__id__": 30
+    },
+    "systemLayer": {
+      "__id__": 45
+    },
+    "_id": "b8tcipoo1AI4Pu80m+21tD"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "PageLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [
+      {
+        "__id__": 9
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 19
+      },
+      {
+        "__id__": 20
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "4bDqmiEC1MOorS2fwqS/ks"
+  },
+  {
+    "__type__": "cc.Node",
+    "_objFlags": 0,
+    "_parent": {
+      "__id__": 8
+    },
+    "_prefab": {
+      "__id__": 10
+    },
+    "__editorExtras__": {}
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 9
+    },
+    "asset": {
+      "__uuid__": "d5aec2d4-3c07-4815-a564-e06bd37d38bf",
+      "__expectedType__": "cc.Prefab"
+    },
+    "fileId": "a5VKIG9nhACpQ/TjQrKkoC",
+    "instance": {
+      "__id__": 11
+    },
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.PrefabInstance",
+    "fileId": "0er0ER1rtHMbyRT6ioL2Si",
+    "prefabRootNode": null,
+    "mountedChildren": [],
+    "mountedComponents": [],
+    "propertyOverrides": [
+      {
+        "__id__": 12
+      },
+      {
+        "__id__": 14
+      },
+      {
+        "__id__": 15
+      },
+      {
+        "__id__": 16
+      },
+      {
+        "__id__": 17
+      }
+    ],
+    "removedComponents": []
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 13
+    },
+    "propertyPath": [
+      "_name"
+    ],
+    "value": "HomeView"
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "a5VKIG9nhACpQ/TjQrKkoC"
+    ]
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 13
+    },
+    "propertyPath": [
+      "_lpos"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 13
+    },
+    "propertyPath": [
+      "_lrot"
+    ],
+    "value": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 13
+    },
+    "propertyPath": [
+      "_euler"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 18
+    },
+    "propertyPath": [
+      "_contentSize"
+    ],
+    "value": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    }
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "ojppqDzaq7QhEkshDmlZyr"
+    ]
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "93wib27k9GioPOcRr+oyZ1"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "e7gHCz0gtECI0F/5UgDnFa"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "WindowLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 22
+      },
+      {
+        "__id__": 23
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "a2VJI79JZJcLXoyXLuCoZx"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 21
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "66X+0SGT5Pkb1z50kAbKil"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 21
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "bbjQPkmXZOrbdZYYJXIEqk"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "PopupLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 25
+      },
+      {
+        "__id__": 26
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "20X3JYaXVGVI5aSE3P6qoe"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 24
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "55Lo6VhPNNDojQGPx6U+Ok"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 24
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "2cSCAOQ4BE5rrK00cIcFfn"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "ToastLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 28
+      },
+      {
+        "__id__": 29
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "1fKcbirFxJkK/OpifX3tpl"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 27
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "50HJSkjLlE6o27tG5o3xPo"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 27
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "29CeCUpC5NOK57zjClXegm"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "LoadingLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [
+      {
+        "__id__": 31
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 43
+      },
+      {
+        "__id__": 44
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "c2J4XuEvlMOKmAkibncviy"
+  },
+  {
+    "__type__": "cc.Node",
+    "_objFlags": 0,
+    "_parent": {
+      "__id__": 30
+    },
+    "_prefab": {
+      "__id__": 32
+    },
+    "__editorExtras__": {}
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 31
+    },
+    "asset": {
+      "__uuid__": "3fad2c76-2dc3-4a9b-8e72-410427e765b6",
+      "__expectedType__": "cc.Prefab"
+    },
+    "fileId": "073EN45qVO75Lrl3dUyoRr",
+    "instance": {
+      "__id__": 33
+    },
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.PrefabInstance",
+    "fileId": "08JHOezcpHHrtkywzxeoXz",
+    "prefabRootNode": null,
+    "mountedChildren": [],
+    "mountedComponents": [
+      {
+        "__id__": 34
+      }
+    ],
+    "propertyOverrides": [
+      {
+        "__id__": 37
+      },
+      {
+        "__id__": 39
+      },
+      {
+        "__id__": 40
+      },
+      {
+        "__id__": 41
+      },
+      {
+        "__id__": 42
+      }
+    ],
+    "removedComponents": []
+  },
+  {
+    "__type__": "cc.MountedComponentsInfo",
+    "targetInfo": {
+      "__id__": 35
+    },
+    "components": [
+      {
+        "__id__": 36
+      }
+    ]
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "073EN45qVO75Lrl3dUyoRr"
+    ]
+  },
+  {
+    "__type__": "c04242DDBVFRbrvXWLJSXxT",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {
+      "mountedRoot": {
+        "__id__": 31
+      }
+    },
+    "node": {
+      "__id__": 31
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "circleNode": null,
+    "_id": "adqYfmwzJHVI/UZnzr43V1"
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 38
+    },
+    "propertyPath": [
+      "_name"
+    ],
+    "value": "LoadingView"
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "073EN45qVO75Lrl3dUyoRr"
+    ]
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 38
+    },
+    "propertyPath": [
+      "_lpos"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 38
+    },
+    "propertyPath": [
+      "_lrot"
+    ],
+    "value": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 38
+    },
+    "propertyPath": [
+      "_euler"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 38
+    },
+    "propertyPath": [
+      "_active"
+    ],
+    "value": false
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 30
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "55vYo03lJBKaiWUsqv4OgN"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 30
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "5dY8zDkatKqaKxePJK3fSf"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "SystemLayer",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 46
+      },
+      {
+        "__id__": 47
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "64eqQ67qNEAJ3OGSNIg3yc"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 45
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "c2DdnvgS5B45bevTyvivni"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 45
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "ffGfRnWWlCFrR3dIzvn03u"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "74smU+XN9L2IeOB6TPUKux"
+  },
+  {
+    "__type__": "cc.Canvas",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_cameraComponent": {
+      "__id__": 3
+    },
+    "_alignCanvasWithScreen": true,
+    "_id": "ffRRZ4fldERJUXD8LzXnEI"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 1280,
+    "_originalHeight": 720,
+    "_alignMode": 1,
+    "_lockFlags": 0,
+    "_id": "52IiaWvbJCEql89Baclexy"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": null,
+    "asset": null,
+    "fileId": "4a86fbd9-0bb0-4388-8633-ac16da3f4e5e",
+    "instance": null,
+    "targetOverrides": [
+      {
+        "__id__": 52
+      }
+    ],
+    "nestedPrefabInstanceRoots": [
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 31
+      }
+    ]
+  },
+  {
+    "__type__": "cc.TargetOverrideInfo",
+    "source": {
+      "__id__": 36
+    },
+    "sourceInfo": null,
+    "propertyPath": [
+      "circleNode"
+    ],
+    "target": {
+      "__id__": 31
+    },
+    "targetInfo": {
+      "__id__": 53
+    }
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "71cPLVGLRGTKqw2oJXF/bt"
+    ]
+  },
+  {
+    "__type__": "cc.SceneGlobals",
+    "ambient": {
+      "__id__": 55
+    },
+    "shadows": {
+      "__id__": 56
+    },
+    "_skybox": {
+      "__id__": 57
+    },
+    "fog": {
+      "__id__": 58
+    },
+    "octree": {
+      "__id__": 59
+    },
+    "skin": {
+      "__id__": 60
+    },
+    "lightProbeInfo": {
+      "__id__": 61
+    },
+    "postSettings": {
+      "__id__": 62
+    },
+    "bakedWithStationaryMainLight": false,
+    "bakedWithHighpLightmap": false
+  },
+  {
+    "__type__": "cc.AmbientInfo",
+    "_skyColorHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyColor": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyIllumHDR": 20000,
+    "_skyIllum": 20000,
+    "_groundAlbedoHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_groundAlbedo": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_skyColorLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 1
+    },
+    "_skyIllumLDR": 20000,
+    "_groundAlbedoLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "cc.ShadowsInfo",
+    "_enabled": false,
+    "_type": 0,
+    "_normal": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 1,
+      "z": 0
+    },
+    "_distance": 0,
+    "_planeBias": 1,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 76
+    },
+    "_maxReceived": 4,
+    "_size": {
+      "__type__": "cc.Vec2",
+      "x": 1024,
+      "y": 1024
+    }
+  },
+  {
+    "__type__": "cc.SkyboxInfo",
+    "_envLightingType": 0,
+    "_envmapHDR": null,
+    "_envmap": null,
+    "_envmapLDR": null,
+    "_diffuseMapHDR": null,
+    "_diffuseMapLDR": null,
+    "_enabled": false,
+    "_useHDR": true,
+    "_editableMaterial": null,
+    "_reflectionHDR": null,
+    "_reflectionLDR": null,
+    "_rotationAngle": 0
+  },
+  {
+    "__type__": "cc.FogInfo",
+    "_type": 0,
+    "_fogColor": {
+      "__type__": "cc.Color",
+      "r": 200,
+      "g": 200,
+      "b": 200,
+      "a": 255
+    },
+    "_enabled": false,
+    "_fogDensity": 0.3,
+    "_fogStart": 0.5,
+    "_fogEnd": 300,
+    "_fogAtten": 5,
+    "_fogTop": 1.5,
+    "_fogRange": 1.2,
+    "_accurate": false
+  },
+  {
+    "__type__": "cc.OctreeInfo",
+    "_enabled": false,
+    "_minPos": {
+      "__type__": "cc.Vec3",
+      "x": -1024,
+      "y": -1024,
+      "z": -1024
+    },
+    "_maxPos": {
+      "__type__": "cc.Vec3",
+      "x": 1024,
+      "y": 1024,
+      "z": 1024
+    },
+    "_depth": 8
+  },
+  {
+    "__type__": "cc.SkinInfo",
+    "_enabled": true,
+    "_blurRadius": 0.01,
+    "_sssIntensity": 3
+  },
+  {
+    "__type__": "cc.LightProbeInfo",
+    "_giScale": 1,
+    "_giSamples": 1024,
+    "_bounces": 2,
+    "_reduceRinging": 0,
+    "_showProbe": true,
+    "_showWireframe": true,
+    "_showConvex": false,
+    "_data": null,
+    "_lightProbeSphereVolume": 1
+  },
+  {
+    "__type__": "cc.PostSettingsInfo",
+    "_toneMappingType": 0
+  }
+]

+ 11 - 0
assets/lobbyRes/scenes/Lobby.scene.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.1.50",
+  "importer": "scene",
+  "imported": true,
+  "uuid": "4a86fbd9-0bb0-4388-8633-ac16da3f4e5e",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/lobbyRes/textures.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "9714cd28-1cae-47f9-b9bd-38648c4b0645",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/lobbyRes/textures/loading.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "bd2510c1-52e9-4fc5-bca6-24811a3ff4d2",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

BIN
assets/lobbyRes/textures/loading/img_loading.png


+ 134 - 0
assets/lobbyRes/textures/loading/img_loading.png.meta

@@ -0,0 +1,134 @@
+{
+  "ver": "1.0.27",
+  "importer": "image",
+  "imported": true,
+  "uuid": "718ee661-a70e-40c1-89dd-3ea180cc3c3c",
+  "files": [
+    ".json",
+    ".png"
+  ],
+  "subMetas": {
+    "6c48a": {
+      "importer": "texture",
+      "uuid": "718ee661-a70e-40c1-89dd-3ea180cc3c3c@6c48a",
+      "displayName": "img_loading",
+      "id": "6c48a",
+      "name": "texture",
+      "userData": {
+        "wrapModeS": "clamp-to-edge",
+        "wrapModeT": "clamp-to-edge",
+        "imageUuidOrDatabaseUri": "718ee661-a70e-40c1-89dd-3ea180cc3c3c",
+        "isUuid": true,
+        "visible": false,
+        "minfilter": "linear",
+        "magfilter": "linear",
+        "mipfilter": "none",
+        "anisotropy": 0
+      },
+      "ver": "1.0.22",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    },
+    "f9941": {
+      "importer": "sprite-frame",
+      "uuid": "718ee661-a70e-40c1-89dd-3ea180cc3c3c@f9941",
+      "displayName": "img_loading",
+      "id": "f9941",
+      "name": "spriteFrame",
+      "userData": {
+        "trimThreshold": 1,
+        "rotated": false,
+        "offsetX": 0,
+        "offsetY": 0,
+        "trimX": 0,
+        "trimY": 0,
+        "width": 240,
+        "height": 240,
+        "rawWidth": 240,
+        "rawHeight": 240,
+        "borderTop": 0,
+        "borderBottom": 0,
+        "borderLeft": 0,
+        "borderRight": 0,
+        "packable": true,
+        "pixelsToUnit": 100,
+        "pivotX": 0.5,
+        "pivotY": 0.5,
+        "meshType": 0,
+        "vertices": {
+          "rawPosition": [
+            -120,
+            -120,
+            0,
+            120,
+            -120,
+            0,
+            -120,
+            120,
+            0,
+            120,
+            120,
+            0
+          ],
+          "indexes": [
+            0,
+            1,
+            2,
+            2,
+            1,
+            3
+          ],
+          "uv": [
+            0,
+            240,
+            240,
+            240,
+            0,
+            0,
+            240,
+            0
+          ],
+          "nuv": [
+            0,
+            0,
+            1,
+            0,
+            0,
+            1,
+            1,
+            1
+          ],
+          "minPos": [
+            -120,
+            -120,
+            0
+          ],
+          "maxPos": [
+            120,
+            120,
+            0
+          ]
+        },
+        "isUuid": true,
+        "imageUuidOrDatabaseUri": "718ee661-a70e-40c1-89dd-3ea180cc3c3c@6c48a",
+        "atlasUuid": "",
+        "trimType": "auto"
+      },
+      "ver": "1.0.12",
+      "imported": true,
+      "files": [
+        ".json"
+      ],
+      "subMetas": {}
+    }
+  },
+  "userData": {
+    "type": "sprite-frame",
+    "fixAlphaTransparencyArtifacts": false,
+    "hasAlpha": true,
+    "redirect": "718ee661-a70e-40c1-89dd-3ea180cc3c3c@6c48a"
+  }
+}

+ 9 - 0
assets/lobbyRes/ui.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "9185043a-da91-450e-83ed-c31adae5f0ff",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/lobbyRes/ui/home.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "8a9ccb42-2e9c-4196-a14f-909f38e26019",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 1025 - 0
assets/lobbyRes/ui/home/HomeView.prefab

@@ -0,0 +1,1025 @@
+[
+  {
+    "__type__": "cc.Prefab",
+    "_name": "HomeView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "data": {
+      "__id__": 1
+    },
+    "optimizationPolicy": 0,
+    "persistent": false
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "HomeView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 8
+      },
+      {
+        "__id__": 14
+      },
+      {
+        "__id__": 20
+      },
+      {
+        "__id__": 28
+      },
+      {
+        "__id__": 32
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 38
+      },
+      {
+        "__id__": 40
+      },
+      {
+        "__id__": 42
+      }
+    ],
+    "_prefab": {
+      "__id__": 44
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 5
+      }
+    ],
+    "_prefab": {
+      "__id__": 7
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 4
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 750
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "17qhVRxOVIEI6teu6Ykgdm"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 6
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 77,
+      "g": 77,
+      "b": 77,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "3fPYh6Bf5H46CH7XYlk3g6"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "2dQiO2xFdO1rOez9j1RwRv",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Title",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 11
+      }
+    ],
+    "_prefab": {
+      "__id__": 13
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 170.374,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 10
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 340.0810546875,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "fepGO2ft70XQ/O0QEcX9ZC"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 12
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 153,
+      "g": 255,
+      "b": 190,
+      "a": 255
+    },
+    "_string": "Lobby Home View",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 42,
+    "_fontSize": 42,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "0ma39xKl4rKOoexRSo1C3D"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "6dCieWCJBLbLLzTM6ARwho",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "lblNickName",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 15
+      },
+      {
+        "__id__": 17
+      }
+    ],
+    "_prefab": {
+      "__id__": 19
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": -24.426000000000045,
+      "y": 25.19999999999999,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 16
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 0,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "02XWhvfnxDoqOjseEgCpYm"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 18
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_string": "",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 20,
+    "_fontSize": 20,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "afP7dogrpM47VLYjUENfot"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "ce7Ceax0dFgK4ap/1U8J2d",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite-001",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 21
+      },
+      {
+        "__id__": 23
+      },
+      {
+        "__id__": 25
+      }
+    ],
+    "_prefab": {
+      "__id__": 27
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": -50.124000000000024,
+      "y": -11.172000000000025,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 20
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 22
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 116.091,
+      "height": 139.643
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "bfKXOB/MlJcomGrpbReb1W"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 20
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 24
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 0,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "27ySIKlkVN5aKNq1mfZAgL"
+  },
+  {
+    "__type__": "53b31priG9PPI8y3djSEn0/",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 20
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 26
+    },
+    "gameIcon": {
+      "__id__": 23
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "d7UeMZaYZNcYGSzucjS1t8"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "22RviZhRdAQqSeQtNUZV3H",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "gameList",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 29
+      }
+    ],
+    "_prefab": {
+      "__id__": 31
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 28
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 30
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "23klO+hblFfqov6/7i3vLy"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "3fIedgS5VHpYCZvU9S5jr1",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite-002",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 33
+      },
+      {
+        "__id__": 35
+      }
+    ],
+    "_prefab": {
+      "__id__": 37
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 205.543,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 32
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 34
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 40,
+      "height": 36
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "74B2tyjEZMWrrhwdoh/5hM"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 32
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 36
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "57520716-48c8-4a19-8acf-41c9f8777fb0@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 0,
+    "_fillType": 0,
+    "_sizeMode": 1,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "67xehZCFRFlLcvCpVVxCee"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "8698lIf3VIaqMSraX1mLaP",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 39
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 750
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "ojppqDzaq7QhEkshDmlZyr"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 41
+    },
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "VWX9vOxlCAWjFDuLOYxHv0"
+  },
+  {
+    "__type__": "2490dDbpyZFI4zY0bCl5FTY",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 43
+    },
+    "lblNickName": {
+      "__id__": 17
+    },
+    "gamePrefab": {
+      "__id__": 25
+    },
+    "gameRoot": {
+      "__id__": 28
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "05IUySUDxOP49f2AJG2Tkn"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "a5VKIG9nhACpQ/TjQrKkoC",
+    "instance": null,
+    "targetOverrides": null
+  }
+]

+ 14 - 0
assets/lobbyRes/ui/home/HomeView.prefab.meta

@@ -0,0 +1,14 @@
+{
+  "ver": "1.1.50",
+  "importer": "prefab",
+  "imported": true,
+  "uuid": "d5aec2d4-3c07-4815-a564-e06bd37d38bf",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {
+    "syncNodeName": "HomeView",
+    "hasIcon": false
+  }
+}

+ 9 - 0
assets/lobbyRes/ui/loading.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "ad71d577-cfea-4423-a8ce-c1b3d479c081",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 476 - 0
assets/lobbyRes/ui/loading/LoadingView.prefab

@@ -0,0 +1,476 @@
+[
+  {
+    "__type__": "cc.Prefab",
+    "_name": "LoadingView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "data": {
+      "__id__": 1
+    },
+    "optimizationPolicy": 0,
+    "persistent": false
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "LoadingView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 10
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 16
+      },
+      {
+        "__id__": 18
+      },
+      {
+        "__id__": 20
+      }
+    ],
+    "_prefab": {
+      "__id__": 22
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite-001",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 5
+      },
+      {
+        "__id__": 7
+      }
+    ],
+    "_prefab": {
+      "__id__": 9
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 4
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "1aTtaxgOFH7aChEOUZYFXG"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 6
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 180
+    },
+    "_spriteFrame": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "09YpyUYxJJZ6EGFcE+VQCl"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 8
+    },
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 40,
+    "_originalHeight": 40,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "612jCbRmNG8p3QiEG1Cswk"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "e3F8Qb9FpOJKGDVGocG5iX",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 11
+      },
+      {
+        "__id__": 13
+      }
+    ],
+    "_prefab": {
+      "__id__": 15
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 10
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 12
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "98n54gIHJK2IAPHo+hdEW6"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 10
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 14
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "718ee661-a70e-40c1-89dd-3ea180cc3c3c@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 0,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "e6lfl67VlPOqQpSMcMApGP"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "71cPLVGLRGTKqw2oJXF/bt",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 17
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 749.9999999999999
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "5aBEukxvlL5LVptNC3T3RT"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 19
+    },
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 40,
+    "_originalHeight": 36,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "80Aw4YRQ5IzbizA27x8uyI"
+  },
+  {
+    "__type__": "cc.BlockInputEvents",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 21
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "e8NSFT2SNOIJRMu0bD6Ees"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "073EN45qVO75Lrl3dUyoRr",
+    "targetOverrides": null
+  }
+]

+ 13 - 0
assets/lobbyRes/ui/loading/LoadingView.prefab.meta

@@ -0,0 +1,13 @@
+{
+  "ver": "1.1.50",
+  "importer": "prefab",
+  "imported": true,
+  "uuid": "3fad2c76-2dc3-4a9b-8e72-410427e765b6",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {
+    "syncNodeName": "LoadingView"
+  }
+}

+ 9 - 0
assets/lobbyRes/ui/login.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "0e0197a1-d56d-48be-afda-18cfe2834f84",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 839 - 0
assets/lobbyRes/ui/login/LoginView.prefab

@@ -0,0 +1,839 @@
+[
+  {
+    "__type__": "cc.Prefab",
+    "_name": "LoginView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "data": {
+      "__id__": 1
+    },
+    "optimizationPolicy": 0,
+    "persistent": false
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "LoginView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 8
+      },
+      {
+        "__id__": 14
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 28
+      },
+      {
+        "__id__": 30
+      },
+      {
+        "__id__": 32
+      }
+    ],
+    "_prefab": {
+      "__id__": 34
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Sprite",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 5
+      }
+    ],
+    "_prefab": {
+      "__id__": 7
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 4
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 750
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "c0hior0xxJXIyLTmi2oDWq"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 6
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 73,
+      "g": 73,
+      "b": 73,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "92hn5mMcNNmrmedW90ZUFv"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "74RUNoOu5HGLAObrdnwodA",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Title",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 11
+      }
+    ],
+    "_prefab": {
+      "__id__": 13
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 10
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 204.708984375,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "1sIvj5/xU+iEB4ycEimanM"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 12
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_string": "Login View",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 42,
+    "_fontSize": 42,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "521hmsI8ZHXWYlPdHMKyC3"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "fdoZ0KghlL1qBflJ0zYkh8",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "btnGuest",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [
+      {
+        "__id__": 15
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 21
+      },
+      {
+        "__id__": 23
+      },
+      {
+        "__id__": 25
+      }
+    ],
+    "_prefab": {
+      "__id__": 27
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": -143.5,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Label",
+    "_objFlags": 512,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 14
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 16
+      },
+      {
+        "__id__": 18
+      }
+    ],
+    "_prefab": {
+      "__id__": 20
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 15
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 17
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 40
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "3da11JahpLj6t0jD50m016"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 15
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 19
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_string": "游客登录",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 20,
+    "_fontSize": 20,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 1,
+    "_enableWrapText": false,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "5afLfLKZdH/6uC+9iDSFvr"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "75X/LUVgNEObDjZIFpeDKs",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 22
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 40
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "15P4LDyHlE+ogDfqOKC/bM"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 24
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "6azv3ZrbpJa7HKzW3CRVNy"
+  },
+  {
+    "__type__": "cc.Button",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 26
+    },
+    "clickEvents": [],
+    "_interactable": true,
+    "_transition": 2,
+    "_normalColor": {
+      "__type__": "cc.Color",
+      "r": 214,
+      "g": 214,
+      "b": 214,
+      "a": 255
+    },
+    "_hoverColor": {
+      "__type__": "cc.Color",
+      "r": 211,
+      "g": 211,
+      "b": 211,
+      "a": 255
+    },
+    "_pressedColor": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_disabledColor": {
+      "__type__": "cc.Color",
+      "r": 124,
+      "g": 124,
+      "b": 124,
+      "a": 255
+    },
+    "_normalSprite": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_hoverSprite": {
+      "__uuid__": "20835ba4-6145-4fbc-a58a-051ce700aa3e@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_pressedSprite": {
+      "__uuid__": "544e49d6-3f05-4fa8-9a9e-091f98fc2ce8@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_disabledSprite": {
+      "__uuid__": "951249e0-9f16-456d-8b85-a6ca954da16b@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_duration": 0.1,
+    "_zoomScale": 1.2,
+    "_target": {
+      "__id__": 14
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "81Umle5pJH278c+/g/h2Sp"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "60EdYBxVpPGaO1uryTZTGF",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 29
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "numEYgChRzLEkacMhSrrjB"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 31
+    },
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "c9NIh+KsUTQkaMufSxiCJk"
+  },
+  {
+    "__type__": "0fef1W7qa5DY6adtEhIyauC",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 33
+    },
+    "btnGuest": {
+      "__id__": 25
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "45XkCQRkxA7ogVra73zhtp"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "095Z9ha5ZMUpYHgvgv8PLj",
+    "instance": null,
+    "targetOverrides": null
+  }
+]

+ 14 - 0
assets/lobbyRes/ui/login/LoginView.prefab.meta

@@ -0,0 +1,14 @@
+{
+  "ver": "1.1.50",
+  "importer": "prefab",
+  "imported": true,
+  "uuid": "995b77a4-66a6-4415-8156-72281cc5a31b",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {
+    "syncNodeName": "LoginView",
+    "hasIcon": false
+  }
+}

+ 14 - 0
assets/resources.meta

@@ -0,0 +1,14 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "a867f729-155b-4d86-809f-099da018310f",
+  "files": [],
+  "subMetas": {},
+  "userData": {
+    "isBundle": true,
+    "bundleConfigID": "default",
+    "bundleName": "resources",
+    "priority": 8
+  }
+}

+ 9 - 0
assets/scenes.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "08f1ed77-0a68-4d44-a285-db0dd65917f1",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 986 - 0
assets/scenes/Launch.scene

@@ -0,0 +1,986 @@
+[
+  {
+    "__type__": "cc.SceneAsset",
+    "_name": "Launch",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "scene": {
+      "__id__": 1
+    }
+  },
+  {
+    "__type__": "cc.Scene",
+    "_name": "Launch",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 4
+      }
+    ],
+    "_active": true,
+    "_components": [],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "autoReleaseAssets": false,
+    "_globals": {
+      "__id__": 23
+    },
+    "_id": "9f2682fb-c657-4518-99a6-10a3af34a002"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Camera",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 667,
+      "y": 374.99999999999994,
+      "z": 1000
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "61BK4xIGZGGK/oNcVxLlQD"
+  },
+  {
+    "__type__": "cc.Camera",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_projection": 0,
+    "_priority": 0,
+    "_fov": 45,
+    "_fovAxis": 0,
+    "_orthoHeight": 416.5695970695971,
+    "_near": 1,
+    "_far": 2000,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 51,
+      "g": 51,
+      "b": 51,
+      "a": 255
+    },
+    "_depth": 1,
+    "_stencil": 0,
+    "_clearFlags": 7,
+    "_rect": {
+      "__type__": "cc.Rect",
+      "x": 0,
+      "y": 0,
+      "width": 1,
+      "height": 1
+    },
+    "_aperture": 19,
+    "_shutter": 7,
+    "_iso": 0,
+    "_screenScale": 1,
+    "_visibility": 1117782015,
+    "_targetTexture": null,
+    "_postProcess": null,
+    "_usePostProcess": false,
+    "_cameraType": -1,
+    "_trackingType": 0,
+    "_id": "f7XGM5lqpBu7KanpQBQNT7"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "AppRoot",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [
+      {
+        "__id__": 5
+      },
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 12
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 19
+      },
+      {
+        "__id__": 20
+      },
+      {
+        "__id__": 21
+      },
+      {
+        "__id__": 22
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 667,
+      "y": 375,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "e2Do3PcMpDAqsGBA2+vrhA"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "background",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 6
+      },
+      {
+        "__id__": 7
+      },
+      {
+        "__id__": 8
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "6cifp0uyFIQoajGZf+ZUDQ"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "9bi6EE9xZMApjl71pnshJS"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 109,
+      "g": 107,
+      "b": 107,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "b730527c-3233-41c2-aaf7-7cdab58f9749@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": "9cpYBIb8VL86QpMmrPne6e"
+  },
+  {
+    "__type__": "cc.BlockInputEvents",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_id": "bchma5q9dFPLu9/Xz2096n"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "ProgressLabel",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 10
+      },
+      {
+        "__id__": 11
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": -40,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "0bCpzCZLRPk52jm3jd2les"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 9
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 163.337890625,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "80lU8pcyNFXaI05UBqvsfY"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 9
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_string": "正在初始化...",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 28,
+    "_fontSize": 28,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": "6dtbAFVRFOwqiTWEJObdAK"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "ProgressBar",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 4
+    },
+    "_children": [
+      {
+        "__id__": 13
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 16
+      },
+      {
+        "__id__": 17
+      },
+      {
+        "__id__": 18
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": -115.90800000000002,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "46pMjsOLdMYICGgTiHGb/N"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Bar",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 12
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 14
+      },
+      {
+        "__id__": 15
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": -260,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "bbVU09w0ZJKYyXz9wFgQkP"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 13
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 520,
+      "height": 28
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0.5
+    },
+    "_id": "6fmuE7fgJCDKPVwWf36mW/"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 13
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "24a704da-2867-446d-8d1a-5e920c75e09d@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": "34HRcxm5ZJSJyVtpLEtUCi"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 12
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 520,
+      "height": 25.583999999999946
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "98JFJq9MVEyodD0dPTilwj"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 12
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "9fd900dd-221b-4f89-8f2c-fba34243c835@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 1,
+    "_fillType": 0,
+    "_sizeMode": 0,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": "ecp9USn4RI476lz0lSN/kz"
+  },
+  {
+    "__type__": "cc.ProgressBar",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 12
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_barSprite": {
+      "__id__": 15
+    },
+    "_mode": 0,
+    "_totalLength": 520,
+    "_progress": 1,
+    "_reverse": false,
+    "_id": "90UqLDIMpEOpygSCsR9jFF"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1334,
+      "height": 750
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "d3qy7wFplAWqbGQkl9WXlz"
+  },
+  {
+    "__type__": "cc.Canvas",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_cameraComponent": {
+      "__id__": 3
+    },
+    "_alignCanvasWithScreen": true,
+    "_id": "f38TXpLhxJCojn6E8ssVt/"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 1280,
+    "_originalHeight": 720,
+    "_alignMode": 1,
+    "_lockFlags": 0,
+    "_id": "40TbjRLKlAEpk7YJNWqrpX"
+  },
+  {
+    "__type__": "4a90aRFfXJBQa+QvSJ3Gy4Z",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 4
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "canvas": {
+      "__id__": 20
+    },
+    "progressLabel": {
+      "__id__": 11
+    },
+    "progressBar": {
+      "__id__": 18
+    },
+    "dialogNode": null,
+    "dialogLabel": null,
+    "dialogConfirmButton": null,
+    "dialogCancelButton": null,
+    "_id": "0d67yrpedDj5dxqWvFI9UK"
+  },
+  {
+    "__type__": "cc.SceneGlobals",
+    "ambient": {
+      "__id__": 24
+    },
+    "shadows": {
+      "__id__": 25
+    },
+    "_skybox": {
+      "__id__": 26
+    },
+    "fog": {
+      "__id__": 27
+    },
+    "octree": {
+      "__id__": 28
+    },
+    "skin": {
+      "__id__": 29
+    },
+    "lightProbeInfo": {
+      "__id__": 30
+    },
+    "postSettings": {
+      "__id__": 31
+    },
+    "bakedWithStationaryMainLight": false,
+    "bakedWithHighpLightmap": false
+  },
+  {
+    "__type__": "cc.AmbientInfo",
+    "_skyColorHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyColor": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 0.520833125
+    },
+    "_skyIllumHDR": 20000,
+    "_skyIllum": 20000,
+    "_groundAlbedoHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_groundAlbedo": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    },
+    "_skyColorLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 1
+    },
+    "_skyIllumLDR": 20000,
+    "_groundAlbedoLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "cc.ShadowsInfo",
+    "_enabled": false,
+    "_type": 0,
+    "_normal": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 1,
+      "z": 0
+    },
+    "_distance": 0,
+    "_planeBias": 1,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 76
+    },
+    "_maxReceived": 4,
+    "_size": {
+      "__type__": "cc.Vec2",
+      "x": 1024,
+      "y": 1024
+    }
+  },
+  {
+    "__type__": "cc.SkyboxInfo",
+    "_envLightingType": 0,
+    "_envmapHDR": null,
+    "_envmap": null,
+    "_envmapLDR": null,
+    "_diffuseMapHDR": null,
+    "_diffuseMapLDR": null,
+    "_enabled": false,
+    "_useHDR": true,
+    "_editableMaterial": null,
+    "_reflectionHDR": null,
+    "_reflectionLDR": null,
+    "_rotationAngle": 0
+  },
+  {
+    "__type__": "cc.FogInfo",
+    "_type": 0,
+    "_fogColor": {
+      "__type__": "cc.Color",
+      "r": 200,
+      "g": 200,
+      "b": 200,
+      "a": 255
+    },
+    "_enabled": false,
+    "_fogDensity": 0.3,
+    "_fogStart": 0.5,
+    "_fogEnd": 300,
+    "_fogAtten": 5,
+    "_fogTop": 1.5,
+    "_fogRange": 1.2,
+    "_accurate": false
+  },
+  {
+    "__type__": "cc.OctreeInfo",
+    "_enabled": false,
+    "_minPos": {
+      "__type__": "cc.Vec3",
+      "x": -1024,
+      "y": -1024,
+      "z": -1024
+    },
+    "_maxPos": {
+      "__type__": "cc.Vec3",
+      "x": 1024,
+      "y": 1024,
+      "z": 1024
+    },
+    "_depth": 8
+  },
+  {
+    "__type__": "cc.SkinInfo",
+    "_enabled": true,
+    "_blurRadius": 0.01,
+    "_sssIntensity": 3
+  },
+  {
+    "__type__": "cc.LightProbeInfo",
+    "_giScale": 1,
+    "_giSamples": 1024,
+    "_bounces": 2,
+    "_reduceRinging": 0,
+    "_showProbe": true,
+    "_showWireframe": true,
+    "_showConvex": false,
+    "_data": null,
+    "_lightProbeSphereVolume": 1
+  },
+  {
+    "__type__": "cc.PostSettingsInfo",
+    "_toneMappingType": 0
+  }
+]

+ 11 - 0
assets/scenes/Launch.scene.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.1.50",
+  "importer": "scene",
+  "imported": true,
+  "uuid": "9f2682fb-c657-4518-99a6-10a3af34a002",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 587 - 0
assets/scenes/Test.scene

@@ -0,0 +1,587 @@
+[
+  {
+    "__type__": "cc.SceneAsset",
+    "_name": "Test",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "scene": {
+      "__id__": 1
+    }
+  },
+  {
+    "__type__": "cc.Scene",
+    "_name": "Test",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      }
+    ],
+    "_active": true,
+    "_components": [],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "autoReleaseAssets": false,
+    "_globals": {
+      "__id__": 13
+    },
+    "_id": "60c57827-b15d-4b16-b79e-7ea2a022ec44"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Canvas",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 5
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 10
+      },
+      {
+        "__id__": 11
+      },
+      {
+        "__id__": 12
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 640,
+      "y": 360,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "f9kb13bYNL65pYw2dFbqnO"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Camera",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 2
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 4
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 1000
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 1073741824,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "c08IxpyQdOt5Ylj7njLG1c"
+  },
+  {
+    "__type__": "cc.Camera",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 3
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_projection": 0,
+    "_priority": 0,
+    "_fov": 45,
+    "_fovAxis": 0,
+    "_orthoHeight": 360,
+    "_near": 0,
+    "_far": 2000,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_depth": 1,
+    "_stencil": 0,
+    "_clearFlags": 7,
+    "_rect": {
+      "__type__": "cc.Rect",
+      "x": 0,
+      "y": 0,
+      "width": 1,
+      "height": 1
+    },
+    "_aperture": 19,
+    "_shutter": 7,
+    "_iso": 0,
+    "_screenScale": 1,
+    "_visibility": 1108344832,
+    "_targetTexture": null,
+    "_postProcess": null,
+    "_usePostProcess": false,
+    "_cameraType": -1,
+    "_trackingType": 0,
+    "_id": "68ah7JNnlHzZsQprpocO9l"
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "webView",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 2
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 6
+      },
+      {
+        "__id__": 7
+      },
+      {
+        "__id__": 8
+      }
+    ],
+    "_prefab": null,
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": "30kSeKB89IJqi3wIkPpLaA"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "cfymSNG1FJ2Lqvu+gjKccd"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 100,
+    "_originalHeight": 100,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "f2NiyVQjJNB7R3e4l0ZMEH"
+  },
+  {
+    "__type__": "cc.WebView",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 5
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_url": "https://www.baidu.com",
+    "webviewEvents": [],
+    "_id": "02EiWUjPdHZYSxe/OTCYte"
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 1280,
+      "height": 720
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": "f0A64wObtGSqtKhkC3I92p"
+  },
+  {
+    "__type__": "cc.Canvas",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_cameraComponent": {
+      "__id__": 4
+    },
+    "_alignCanvasWithScreen": true,
+    "_id": "cdPEBzlk5O4rFBTJ5Df7av"
+  },
+  {
+    "__type__": "cc.Widget",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "_alignFlags": 45,
+    "_target": null,
+    "_left": 0,
+    "_right": 0,
+    "_top": 0,
+    "_bottom": 0,
+    "_horizontalCenter": 0,
+    "_verticalCenter": 0,
+    "_isAbsLeft": true,
+    "_isAbsRight": true,
+    "_isAbsTop": true,
+    "_isAbsBottom": true,
+    "_isAbsHorizontalCenter": true,
+    "_isAbsVerticalCenter": true,
+    "_originalWidth": 0,
+    "_originalHeight": 0,
+    "_alignMode": 2,
+    "_lockFlags": 0,
+    "_id": "118uzAQANALoVyT3wzKPMW"
+  },
+  {
+    "__type__": "c4ceeXZmQJAyY6/pBFi7Cwk",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": null,
+    "webView": {
+      "__id__": 8
+    },
+    "_id": "68nuuLXylOuKTMM1My38bv"
+  },
+  {
+    "__type__": "cc.SceneGlobals",
+    "ambient": {
+      "__id__": 14
+    },
+    "shadows": {
+      "__id__": 15
+    },
+    "_skybox": {
+      "__id__": 16
+    },
+    "fog": {
+      "__id__": 17
+    },
+    "octree": {
+      "__id__": 18
+    },
+    "skin": {
+      "__id__": 19
+    },
+    "lightProbeInfo": {
+      "__id__": 20
+    },
+    "postSettings": {
+      "__id__": 21
+    },
+    "bakedWithStationaryMainLight": false,
+    "bakedWithHighpLightmap": false
+  },
+  {
+    "__type__": "cc.AmbientInfo",
+    "_skyColorHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 0.520833125
+    },
+    "_skyColor": {
+      "__type__": "cc.Vec4",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 0.520833125
+    },
+    "_skyIllumHDR": 20000,
+    "_skyIllum": 20000,
+    "_groundAlbedoHDR": {
+      "__type__": "cc.Vec4",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 0
+    },
+    "_groundAlbedo": {
+      "__type__": "cc.Vec4",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 0
+    },
+    "_skyColorLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.5,
+      "z": 0.8,
+      "w": 1
+    },
+    "_skyIllumLDR": 20000,
+    "_groundAlbedoLDR": {
+      "__type__": "cc.Vec4",
+      "x": 0.2,
+      "y": 0.2,
+      "z": 0.2,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "cc.ShadowsInfo",
+    "_enabled": false,
+    "_type": 0,
+    "_normal": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 1,
+      "z": 0
+    },
+    "_distance": 0,
+    "_planeBias": 1,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 76,
+      "g": 76,
+      "b": 76,
+      "a": 255
+    },
+    "_maxReceived": 4,
+    "_size": {
+      "__type__": "cc.Vec2",
+      "x": 512,
+      "y": 512
+    }
+  },
+  {
+    "__type__": "cc.SkyboxInfo",
+    "_envLightingType": 0,
+    "_envmapHDR": null,
+    "_envmap": null,
+    "_envmapLDR": null,
+    "_diffuseMapHDR": null,
+    "_diffuseMapLDR": null,
+    "_enabled": false,
+    "_useHDR": true,
+    "_editableMaterial": null,
+    "_reflectionHDR": null,
+    "_reflectionLDR": null,
+    "_rotationAngle": 0
+  },
+  {
+    "__type__": "cc.FogInfo",
+    "_type": 0,
+    "_fogColor": {
+      "__type__": "cc.Color",
+      "r": 200,
+      "g": 200,
+      "b": 200,
+      "a": 255
+    },
+    "_enabled": false,
+    "_fogDensity": 0.3,
+    "_fogStart": 0.5,
+    "_fogEnd": 300,
+    "_fogAtten": 5,
+    "_fogTop": 1.5,
+    "_fogRange": 1.2,
+    "_accurate": false
+  },
+  {
+    "__type__": "cc.OctreeInfo",
+    "_enabled": false,
+    "_minPos": {
+      "__type__": "cc.Vec3",
+      "x": -1024,
+      "y": -1024,
+      "z": -1024
+    },
+    "_maxPos": {
+      "__type__": "cc.Vec3",
+      "x": 1024,
+      "y": 1024,
+      "z": 1024
+    },
+    "_depth": 8
+  },
+  {
+    "__type__": "cc.SkinInfo",
+    "_enabled": false,
+    "_blurRadius": 0.01,
+    "_sssIntensity": 3
+  },
+  {
+    "__type__": "cc.LightProbeInfo",
+    "_giScale": 1,
+    "_giSamples": 1024,
+    "_bounces": 2,
+    "_reduceRinging": 0,
+    "_showProbe": true,
+    "_showWireframe": true,
+    "_showConvex": false,
+    "_data": null,
+    "_lightProbeSphereVolume": 1
+  },
+  {
+    "__type__": "cc.PostSettingsInfo",
+    "_toneMappingType": 0
+  }
+]

+ 11 - 0
assets/scenes/Test.scene.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "1.1.50",
+  "importer": "scene",
+  "imported": true,
+  "uuid": "60c57827-b15d-4b16-b79e-7ea2a022ec44",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "0cbec635-da28-4519-a9e7-40883d404112",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 23 - 0
assets/scripts/Test.ts

@@ -0,0 +1,23 @@
+import { _decorator, Component, Node, WebView } from 'cc';
+const { ccclass, property } = _decorator;
+
+@ccclass('Test')
+export class Test extends Component {
+
+    @property(WebView)
+    webView: WebView = null;
+
+    start() {
+        setTimeout(() => {
+            const parent = this.webView.nativeWebView.parentElement;
+            
+        }, 1000);
+
+    }
+
+    update(deltaTime: number) {
+
+    }
+}
+
+

+ 9 - 0
assets/scripts/Test.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "c4cee5d9-9902-40c9-8ebf-a41162ec2c24",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/api.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "ab013e62-c403-4399-90c9-5453f614e08b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 18 - 0
assets/scripts/api/Config.ts

@@ -0,0 +1,18 @@
+import AppConfig from '../app/AppConfig';
+import { ApiEndpoint, ApiEnvelope } from '../request/RequestTypes';
+
+export const API_BASE_PREFIX = 'game/';
+
+export const API_BASE_URL = AppConfig.IsDebugEnv ? AppConfig.TestApiUrl : AppConfig.MainApiUrl;
+
+export const API_BASE_WS = AppConfig.IsDebugEnv ? AppConfig.TestWsUrl : AppConfig.MainWsUrl;
+
+export const get = (path: string): ApiEndpoint => ({ method: 'GET', path });
+
+export const post = (path: string): ApiEndpoint => ({ method: 'POST', path });
+
+export const API_CODE_SUCCESS = 200;
+
+export const success = (res: ApiEnvelope) => {
+    return res && (res.code === 0 || res.code === 200);
+}

+ 9 - 0
assets/scripts/api/Config.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "5c507c97-ac23-418e-8c10-078c1d5b77a5",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 29 - 0
assets/scripts/api/LobbyApi.ts

@@ -0,0 +1,29 @@
+import { API_BASE_PREFIX, get, post } from './Config';
+
+export const APP_ROUTES = get(API_BASE_PREFIX + 'routes');
+export const APP_PAGE_MODULE = API_BASE_PREFIX + 'pageModules/';
+export const APP_GAME_LIST = get(API_BASE_PREFIX + 'gameList');
+export const APP_GAME_CARD_INFO = get(API_BASE_PREFIX + 'gameinfo');
+export const APP_GAME_ENTER_RECORD = get(API_BASE_PREFIX + 'game_enter/record');
+
+export const APP_FAVORITE_ADD = get(API_BASE_PREFIX + 'favo/add');
+export const APP_FAVORITE_REMOVE = get(API_BASE_PREFIX + 'favo/remove');
+export const APP_FAVORITE_GET = get(API_BASE_PREFIX + 'favo/get');
+
+export const APP_SERVICE = get(API_BASE_PREFIX + 'service');
+export const APP_USER_MESSAGE = get(API_BASE_PREFIX + 'user/message');
+export const APP_MAIL_LIST = get(API_BASE_PREFIX + 'mail/list');
+export const APP_MAIL_CHECK = get(API_BASE_PREFIX + 'mail/check');
+export const APP_MAIL_READ = get(API_BASE_PREFIX + 'mail/read');
+export const APP_MAIL_DELETE = get(API_BASE_PREFIX + 'mail/del');
+export const APP_MAIL_TAKE = get(API_BASE_PREFIX + 'mail/take');
+
+
+export const APP_CHECKIN_CHECK = get(API_BASE_PREFIX + 'checkin/check');
+export const APP_CHECKIN_GET = get(API_BASE_PREFIX + 'checkin/get');
+
+export const APP_PROTECT_CHECK = get(API_BASE_PREFIX + 'protect/check');
+export const APP_PROTECT_GET = get(API_BASE_PREFIX + 'protect/get');
+
+export const APP_LOG = post(API_BASE_PREFIX + 'log');
+

+ 9 - 0
assets/scripts/api/LobbyApi.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "f67314cb-1d73-40c1-b84b-36526953221a",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 37 - 0
assets/scripts/api/LoginApi.ts

@@ -0,0 +1,37 @@
+import { API_BASE_PREFIX, get, post } from './Config';
+
+export const API_LOGIN = post(API_BASE_PREFIX + 'login');
+
+export const API_REGISTER = post(API_BASE_PREFIX + 'register');
+
+export const API_GET_REGISTER_GOLD = post(API_BASE_PREFIX + 'getRegisterGold');
+
+export const API_LOGOUT = get(API_BASE_PREFIX + 'logout');
+
+export const API_RESET_LOGIN_STATE = get(API_BASE_PREFIX + 'resetLoginState');
+
+export const API_USER_INFO = get(API_BASE_PREFIX + 'info');
+
+export const API_CHANGE_INFO = post(API_BASE_PREFIX + 'changeInfo');
+
+export const API_CHANGE_PASS = post(API_BASE_PREFIX + 'changePass');
+
+export const API_CHANGE_PHONE = post(API_BASE_PREFIX + 'changePhone');
+
+export const API_CHANGE_EMAIL = post(API_BASE_PREFIX + 'changeEmail');
+
+export const API_SEND_CODE = get(API_BASE_PREFIX + 'send_code');
+
+export const API_BIND_SMS = post(API_BASE_PREFIX + 'bindsms');
+
+export const API_SMS_LOGIN = post(API_BASE_PREFIX + 'smslogin');
+
+export const API_FORGET_PASS = post(API_BASE_PREFIX + 'forgetPass');
+
+export const API_CHANGE_PHONE_VERIFY = post(API_BASE_PREFIX + 'changePhoneVerify');
+
+export const API_CHANGE_BIND_PHONE = post(API_BASE_PREFIX + 'changeBindPhone');
+
+export const API_CHANGE_LIMIT_INFO = get(API_BASE_PREFIX + 'changeLimitInfo');
+
+export const API_COUNTRY_CODE = get(API_BASE_PREFIX + 'country_code');

+ 9 - 0
assets/scripts/api/LoginApi.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "c4f557eb-fda1-40d0-b367-19b6bce1449c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 41 - 0
assets/scripts/api/PaymentApi.ts

@@ -0,0 +1,41 @@
+import { API_BASE_PREFIX, get, post } from './Config';
+
+export const API_RECHARGE_GEAR = get(API_BASE_PREFIX + 'recharge/gear');
+
+export const API_FIRST_PAY_CONFIG = get(API_BASE_PREFIX + 'recharge/firstPayConfig');
+
+export const API_ACCOUNTS_PAY_INFO = get(API_BASE_PREFIX + 'api/get_accounts_pay_info');
+
+export const API_PAYMENT_PAY = get(API_BASE_PREFIX + 'payment_entry/pay');
+
+export const API_PAYMENT_PAY_QR = get(API_BASE_PREFIX + 'payment_entry/payqr');
+
+export const API_PAY_ORDER_LIST = get(API_BASE_PREFIX + 'pay/orderList');
+
+export const API_FIRST_PAY_MULTI = get(API_BASE_PREFIX + 'pay/first_pay_multi');
+
+export const API_SECOND_PAY_REWARD = get(API_BASE_PREFIX + 'pay/get_second');
+
+export const API_KYC_EU = post(API_BASE_PREFIX + 'kyc/eu');
+
+export const API_FIRST_PAY_GIFT = get(API_BASE_PREFIX + 'pay/first_pay_gift');
+
+export const API_CLAIM_FIRST_PAY_GIFT = get(API_BASE_PREFIX + 'pay/claim_first_pay_gift');
+
+export const API_BANKRUPTCY_GIFT = get(API_BASE_PREFIX + 'pay/bankruptcy_gift');
+
+export const API_DAILY_FIRST_RECHARGE_GIFT = get(API_BASE_PREFIX + 'pay/daily_first_recharge_gift');
+
+export const API_DAILY_GIFT = get(API_BASE_PREFIX + 'pay/daily_gift');
+
+export const API_CLAIM_DAILY_GIFT_BONUS = post(API_BASE_PREFIX + 'pay/claim_daily_gift_bonus');
+
+export const API_FREE_BONUS_GIFT = get(API_BASE_PREFIX + 'pay/free_bonus_gift');
+
+export const API_VIP_INACTIVE_GIFT = post(API_BASE_PREFIX + 'pay/vip_inactive_gift');
+
+export const API_VIP_INACTIVE_GIFT_INFO = post(API_BASE_PREFIX + 'pay/vip_inactive_gift_info');
+
+export const API_CLAIM_VIP_INACTIVE_GIFT_DAY = post(API_BASE_PREFIX + 'pay/claim_vip_inactive_gift_day');
+
+export const API_COUPON_LIST = get(API_BASE_PREFIX + 'coupon/list');

+ 9 - 0
assets/scripts/api/PaymentApi.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "93a61e1e-b0b8-487b-83f5-c8484193d12c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 29 - 0
assets/scripts/api/WalletApi.ts

@@ -0,0 +1,29 @@
+import { API_BASE_PREFIX, get, post } from './Config';
+
+export const API_WITHDRAW_TAX = get('api/api/withDrawTax');
+
+export const API_WITHDRAW_BASE_INFO = post(API_BASE_PREFIX + 'withDraw/baseInfo');
+
+export const API_GET_WITHDRAW_INFO = post(API_BASE_PREFIX + 'withDraw/getWithDrawInfo');
+
+export const API_CHANGE_PAY_PASS = post(API_BASE_PREFIX + 'changePayPass');
+
+export const API_FORGET_PAY_PASS = post(API_BASE_PREFIX + 'forgetPayPass');
+
+export const API_WITHDRAW_RECORD = post(API_BASE_PREFIX + 'withDraw/record');
+
+export const API_SAVE_WITHDRAW_INFO = post(API_BASE_PREFIX + 'withDraw/withDrawInfo');
+
+export const API_SAVE_MEXICO_WITHDRAW_INFO = post(API_BASE_PREFIX + 'withDraw/mexWithDrawInfo');
+
+export const API_SAVE_RUSSIA_WITHDRAW_INFO = post(API_BASE_PREFIX + 'withDraw/ruWithDrawInfo');
+
+export const API_SAVE_CPF = get(API_BASE_PREFIX + 'withDraw/savecpf');
+
+export const API_WITHDRAW_PAYOUT = post(API_BASE_PREFIX + 'withDraw/payout');
+
+export const API_FREE_WITHDRAW_INFO = get(API_BASE_PREFIX + 'withDraw/freeWithDrawInfo');
+
+export const API_VIP_WITHDRAW_TASKS = get(API_BASE_PREFIX + 'vip-withdraw/tasks');
+
+export const API_VIP_WITHDRAW_CLAIM = get(API_BASE_PREFIX + 'vip-withdraw/claim');

+ 9 - 0
assets/scripts/api/WalletApi.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "fbe89f97-1b8c-44f7-b6d1-0d4b8d914c7c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 5 - 0
assets/scripts/api/index.ts

@@ -0,0 +1,5 @@
+export * from './Config';
+export * from './LobbyApi';
+export * from './LoginApi';
+export * from './PaymentApi';
+export * from './WalletApi';

+ 9 - 0
assets/scripts/api/index.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "566e7591-8692-4a18-93b9-9031dd949c5e",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/app.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "23e691ea-5d2b-4828-8135-fc20abf5e3b1",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 22 - 0
assets/scripts/app/AppConfig.ts

@@ -0,0 +1,22 @@
+
+const AppConfig = {
+    /** 测试环境 */
+    IsDebugEnv: true,
+    ProductName: "lionhalo",
+    ProductID: "1",
+
+    MainApiUrl: "https://testapi.usgamewin.com/",
+    MainWsUrl: "wss://testapi.usgamewin.com:10000",
+    TestApiUrl: "https://testapi.usgamewin.com/",
+    TestWsUrl: "wss://testapi.usgamewin.com:10000",
+    GameScheme: "game2c",
+
+    /**
+     * 可选的热更新地址覆盖。留空时使用 project.manifest 中的地址;
+     * 非空时使用本地 Manifest 的资源列表与该地址下的远端 Manifest 做检测。
+     */
+    HotUpdateUrl: "",
+    HotUpdateEnable: true,
+};
+
+export default AppConfig;

+ 9 - 0
assets/scripts/app/AppConfig.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "44c50605-830e-42e3-b923-863286aa810e",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 22 - 0
assets/scripts/app/AppEvents.ts

@@ -0,0 +1,22 @@
+import type {
+  HallCallClientMessage,
+  HallMessage,
+  HallPayFinishMessage,
+} from '../services/hall/HallService';
+
+export interface AppEventMap {
+  'launch:completed': undefined,
+  'network:changed': boolean;
+  'login:success': undefined,
+  'game:entered': undefined;
+  'game:exited': { gameId: string; reason: string };
+  'app:pause': undefined;
+  'app:resume': undefined;
+  'hall:connected': undefined;
+  'hall:disconnected': { code?: number };
+  'hall:timeout': undefined;
+  'hall:kicked': HallMessage;
+  'hall:message': { type: string; message: HallMessage };
+  'hall:pay-finished': HallPayFinishMessage;
+  'hall:call-client': HallCallClientMessage;
+}

+ 9 - 0
assets/scripts/app/AppEvents.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "7f399237-68e6-4243-963c-e871ec75a5d3",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 87 - 0
assets/scripts/app/AppKernel.ts

@@ -0,0 +1,87 @@
+import { ANDROID, HTML5, IOS } from 'cc/env';
+import type { AppEventMap } from './AppEvents';
+import { EventManager } from '../framework/event/EventManager';
+import { ResourceManager } from '../framework/resource/ResourceManager';
+import { SceneNavigator } from '../framework/scene/SceneNavigator';
+import { UIManager } from '../framework/ui/UIManager';
+import { AndroidPlatformBridge } from '../platform/AndroidPlatformBridge';
+import { H5PlatformBridge } from '../platform/H5PlatformBridge';
+import { IOSPlatformBridge } from '../platform/IOSPlatformBridge';
+import { PlatformBridge } from '../platform/PlatformBridge';
+import { HotUpdateService } from '../services/hotupdate/HotUpdateService';
+import { VersionService } from '../services/version/VersionService';
+import * as stores from '../store';
+import * as services from '../services';
+
+
+export class AppKernel {
+  private static instance: AppKernel | null = null;
+
+  static initialize(): AppKernel {
+    if (!this.instance) {
+      this.instance = new AppKernel();
+    }
+    return this.instance;
+  }
+
+  static get Instance(): AppKernel {
+    if (!this.instance) throw new Error('AppKernel has not been initialized');
+    return this.instance;
+  }
+
+  static get events(): EventManager<AppEventMap> {
+    return this.Instance.events;
+  }
+
+  static get resources(): ResourceManager {
+    return this.Instance.resources;
+  }
+
+  static get ui(): UIManager {
+    return this.Instance.ui;
+  }
+
+  static get scenes(): SceneNavigator {
+    return this.Instance.scenes;
+  }
+
+  static get version(): VersionService {
+    return this.Instance.version;
+  }
+
+  static get hotUpdate(): HotUpdateService {
+    return this.Instance.hotUpdate;
+  }
+
+  static get platform(): PlatformBridge {
+    return this.Instance.platform;
+  }
+
+  static get stores(): typeof stores {
+    return this.Instance.stores;
+  }
+
+  static get services(): typeof services {
+    return this.Instance.services;
+  }
+
+  readonly events = new EventManager<AppEventMap>();
+  readonly resources = new ResourceManager();
+  readonly ui = new UIManager(this.resources);
+  readonly scenes = new SceneNavigator(this.resources);
+  readonly version = new VersionService();
+  readonly hotUpdate = new HotUpdateService();
+  readonly platform: PlatformBridge;
+  readonly stores = stores;
+  readonly services = services;
+
+  private constructor() {
+    this.platform = this.createPlatformBridge();
+  }
+
+  private createPlatformBridge(): PlatformBridge {
+    if (ANDROID) return new AndroidPlatformBridge();
+    if (IOS) return new IOSPlatformBridge();
+    return new H5PlatformBridge();
+  }
+}

+ 9 - 0
assets/scripts/app/AppKernel.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "c3e03c71-8a2f-41a1-8fd9-89f5ed594c75",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/components.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "482f7989-57ea-436d-9640-f681a6191975",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/constants.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "6a33b92b-e084-4d5a-86ee-be8e1d06efa6",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 7 - 0
assets/scripts/constants/Localkey.ts

@@ -0,0 +1,7 @@
+export const LOCAL_SIGN = "G_SIGN";
+
+export const LOCAL_ACTIVITY_C = "LOCAL_ACTIVITY_C";
+
+export const LOCAL_FINGERPRINT_KEY = "LOCAL_FINGERPRINT_KEY";
+
+export const LOCAL_DEVICE_CODE = "LOCAL_DEVICE_CODE";

+ 9 - 0
assets/scripts/constants/Localkey.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "de51a7b8-3e27-4c4c-8bc2-d2d9b6cb0e61",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/define.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "7c404728-b3d3-407e-bf58-bfeed8ca081a",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/define/AppConfig.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "1a8083fa-5425-457a-a342-4dae8e4d9209",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 14 - 0
assets/scripts/define/Define.ts

@@ -0,0 +1,14 @@
+import { API_BASE_WS } from "../api"
+
+export const LoginType = {
+    ID: "id",
+    PHONE: "phone",
+    SMS: "sms",
+    MAIL: "mail",
+    GUEST: "guest"
+}
+
+export const APP_SERVER = {
+    SERVER_URL: API_BASE_WS,
+    ROOM_HALL: "hall",
+}

+ 9 - 0
assets/scripts/define/Define.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "036f531e-df7a-4d05-aaf3-7351cc5af6db",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 3 - 0
assets/scripts/define/ResDefine.ts

@@ -0,0 +1,3 @@
+export const BUNDLE_ID = {
+    Lobby: "lobbyRes",
+}

+ 9 - 0
assets/scripts/define/ResDefine.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "3d728bd2-06aa-4019-ae4a-f77d15367852",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 44 - 0
assets/scripts/define/UIDefine.ts

@@ -0,0 +1,44 @@
+import { UICachePolicy, UILayer } from '../framework/ui/UILayer';
+// viewId.StoreView
+export const UIViewID = {
+    LoginView: 'LoginView',
+    HomeView: 'HomeView',
+    LoadingView: "LoadingView",
+} as const;
+
+export type UIViewID = typeof UIViewID[keyof typeof UIViewID];
+export interface UIViewConfig {
+    id: UIViewID;
+    prefabPath: string;
+    layer: UILayer;
+    bundle?: string;
+    cache?: UICachePolicy;
+    mutexGroup?: string;
+}
+
+/**
+ * 项目全部 UIView 的静态配置。
+ */
+export const UIViewConfigs: Record<string, UIViewConfig> = {
+    [UIViewID.LoginView]: {
+        id: UIViewID.LoginView,
+        prefabPath: 'ui/login/LoginView',
+        layer: UILayer.Page,
+    },
+    [UIViewID.HomeView]: {
+        id: UIViewID.HomeView,
+        prefabPath: 'ui/home/HomeView',
+        layer: UILayer.Page,
+        cache: UICachePolicy.Persist,
+    },
+    [UIViewID.LoadingView]: {
+        id: UIViewID.LoadingView,
+        prefabPath: 'ui/loading/LoadingView',
+        layer: UILayer.Loading,
+        cache: UICachePolicy.Persist,
+    },
+};
+
+export function getUIViewConfig(viewId: UIViewID): UIViewConfig {
+    return UIViewConfigs[viewId];
+}

+ 9 - 0
assets/scripts/define/UIDefine.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "34bfe02e-0551-48ca-a2a9-cbe08cf77c8b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "e23cbf77-2caf-4a84-8ca2-369941d04e39",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework/event.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "0147dcb8-639c-4505-b971-8a8b945522dc",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 74 - 0
assets/scripts/framework/event/EventManager.ts

@@ -0,0 +1,74 @@
+interface EventListener<T = unknown> {
+  callback: (payload: T) => void;
+  target?: unknown;
+  once: boolean;
+}
+
+export class EventManager<TEvents extends object = Record<string, unknown>> {
+  private readonly listeners = new Map<keyof TEvents, Set<EventListener>>();
+
+  on<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
+    this.add(event, callback, target, false);
+  }
+
+  once<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
+    this.add(event, callback, target, true);
+  }
+
+  off<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void {
+    const bucket = this.listeners.get(event);
+    if (!bucket) return;
+
+    for (const listener of bucket) {
+      if (listener.callback === callback && listener.target === target) {
+        bucket.delete(listener);
+      }
+    }
+
+    if (bucket.size === 0) this.listeners.delete(event);
+  }
+
+  offTarget(target: unknown): void {
+    for (const [event, bucket] of this.listeners) {
+      for (const listener of bucket) {
+        if (listener.target === target) bucket.delete(listener);
+      }
+      if (bucket.size === 0) this.listeners.delete(event);
+    }
+  }
+
+  emit<K extends keyof TEvents>(event: K, payload?: TEvents[K]): void {
+    const bucket = this.listeners.get(event);
+    if (!bucket) return;
+
+    for (const listener of [...bucket]) {
+      try {
+        (listener.callback as (value: TEvents[K]) => void).call(listener.target, payload);
+      } catch (error) {
+        console.error(`[EventManager] listener failed: ${String(event)}`, error);
+      }
+
+      if (listener.once) bucket.delete(listener);
+    }
+
+    if (bucket.size === 0) this.listeners.delete(event);
+  }
+
+  clear(): void {
+    this.listeners.clear();
+  }
+
+  private add<K extends keyof TEvents>(event: K, callback: (payload: TEvents[K]) => void, target: unknown, once: boolean): void {
+    let bucket = this.listeners.get(event);
+    if (!bucket) {
+      bucket = new Set<EventListener>();
+      this.listeners.set(event, bucket);
+    }
+
+    for (const listener of bucket) {
+      if (listener.callback === callback && listener.target === target) return;
+    }
+
+    bucket.add({ callback: callback as (payload: unknown) => void, target, once });
+  }
+}

+ 9 - 0
assets/scripts/framework/event/EventManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "93a72668-fdf0-4239-86ac-d15e5ff34151",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework/resource.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "e2b68002-df33-47e9-8b33-ec0681a7d32f",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 78 - 0
assets/scripts/framework/resource/ResourceManager.ts

@@ -0,0 +1,78 @@
+import { Asset, assetManager, AssetManager, ImageAsset, Prefab, SpriteFrame } from 'cc';
+
+export enum ResourceScope {
+  App = 'app',
+  Scene = 'scene',
+  View = 'view',
+}
+
+export class ResourceManager {
+  private readonly bundles = new Map<string, AssetManager.Bundle>();
+
+  async loadBundle(name: string): Promise<AssetManager.Bundle> {
+    const cached = this.bundles.get(name) ?? assetManager.getBundle(name);
+    if (cached) {
+      this.bundles.set(name, cached);
+      return cached;
+    }
+
+    return new Promise((resolve, reject) => {
+      assetManager.loadBundle(name, (error, bundle) => {
+        if (error || !bundle) {
+          reject(error ?? new Error(`Bundle not found: ${name}`));
+          return;
+        }
+        this.bundles.set(name, bundle);
+        resolve(bundle);
+      });
+    });
+  }
+
+  async load<T extends Asset>(
+    bundleName: string,
+    path: string,
+    type: new (...args: never[]) => T,
+  ): Promise<T> {
+    const bundle = await this.loadBundle(bundleName);
+    return new Promise((resolve, reject) => {
+      bundle.load(path, type, (error, asset) => {
+        if (error || !asset) {
+          reject(error ?? new Error(`Asset not found: ${bundleName}/${path}`));
+          return;
+        }
+        resolve(asset as T);
+      });
+    });
+  }
+
+  loadPrefab(bundleName: string, path: string): Promise<Prefab> {
+    return this.load(bundleName, path, Prefab);
+  }
+
+  releaseBundle(name: string): void {
+    const bundle = this.bundles.get(name);
+    if (!bundle) return;
+    bundle.releaseAll();
+    assetManager.removeBundle(bundle);
+    this.bundles.delete(name);
+  }
+
+  async loadRemoteSp(url: string): Promise<SpriteFrame | null> {
+    const img = await this.loadRemoteRes<ImageAsset>(url);
+    const sp = SpriteFrame.createWithImage(img);
+    return sp;
+  }
+
+  async loadRemoteRes<T extends Asset>(url: string): Promise<T | null> {
+    return new Promise<T>((resolve, reject) => {
+      assetManager.loadRemote<T>(url, (err, res) => {
+        if (err) {
+          console.error(err, url);
+          resolve(null);
+          return;
+        }
+        resolve(res);
+      });
+    })
+  }
+}

+ 9 - 0
assets/scripts/framework/resource/ResourceManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "a8dd7bd6-9427-432c-9cfd-c660ea20c99b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework/scene.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "0c9a5115-f914-4967-ad81-b7d957a24b92",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 72 - 0
assets/scripts/framework/scene/SceneNavigator.ts

@@ -0,0 +1,72 @@
+import { director } from 'cc';
+import { BUNDLE_ID } from '../../define/ResDefine';
+import { ResourceManager } from '../resource/ResourceManager';
+
+export enum SceneId {
+  Launch = 'Launch',
+  Lobby = 'Lobby',
+  Game = 'Game',
+}
+
+const SceneRes = {
+  [SceneId.Lobby]: BUNDLE_ID.Lobby,
+  [SceneId.Game]: BUNDLE_ID.Lobby
+}
+
+export class SceneNavigator {
+  private navigating = false;
+
+  constructor(private readonly resLoader: ResourceManager) { }
+
+  async preload(scene: SceneId): Promise<void> {
+
+    const bundleName = SceneRes[scene];
+    if (bundleName) {
+      await this.resLoader.loadBundle(bundleName);
+    }
+
+    return new Promise((resolve, reject) => {
+      director.preloadScene(scene, (error) => {
+        if (error) {
+          console.log('preload scene error: ', error);
+          reject(error);
+          return;
+        }
+
+        resolve();
+      });
+    });
+  }
+
+  async go(scene: SceneId): Promise<void> {
+    if (this.navigating || director.getScene()?.name === scene) return;
+    this.navigating = true;
+    try {
+
+      const bundleName = SceneRes[scene];
+      if (bundleName) {
+        await this.resLoader.loadBundle(bundleName);
+      }
+
+      await new Promise<void>((resolve, reject) => {
+        director.loadScene(scene, (error) => {
+          if (error) {
+            console.log('load scene error: ', error);
+            reject(error);
+            return;
+          }
+
+          resolve();
+        });
+      });
+    } finally {
+      this.navigating = false;
+    }
+  }
+
+  goToLobby(): Promise<void> { return this.go(SceneId.Lobby); }
+  goToGame(): Promise<void> {
+
+    return this.go(SceneId.Game);
+  }
+}

+ 9 - 0
assets/scripts/framework/scene/SceneNavigator.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "d6a5b595-bfd7-4d26-9262-68800fac9629",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework/state.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "ac635ecf-af44-4e00-a277-e315c4c75022",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 69 - 0
assets/scripts/framework/state/AsyncStateMachine.ts

@@ -0,0 +1,69 @@
+export type StateHandler<TState extends string> = () => Promise<TState | null>;
+
+export interface StateTransition<TState extends string> {
+  from: TState | null;
+  to: TState;
+}
+
+/**
+ * 顺序异步状态机。
+ *
+ * 每个状态完成后返回下一个状态,返回 null 表示流程结束。
+ * 状态处理器抛出的异常由调用方决定如何进入失败状态。
+ */
+export class AsyncStateMachine<TState extends string> {
+  private readonly handlers = new Map<TState, StateHandler<TState>>();
+  private currentState: TState | null = null;
+  private running = false;
+
+  constructor(
+    private readonly onTransition?: (transition: StateTransition<TState>) => void,
+  ) {}
+
+  get current(): TState | null {
+    return this.currentState;
+  }
+
+  register(state: TState, handler: StateHandler<TState>): this {
+    if (this.handlers.has(state)) {
+      throw new Error(`State already registered: ${state}`);
+    }
+    this.handlers.set(state, handler);
+    return this;
+  }
+
+  async start(initialState: TState): Promise<void> {
+    if (this.running) {
+      throw new Error('State machine is already running');
+    }
+
+    this.running = true;
+    try {
+      let nextState: TState | null = initialState;
+      while (nextState !== null) {
+        nextState = await this.execute(nextState);
+      }
+    } finally {
+      this.running = false;
+    }
+  }
+
+  async transition(state: TState): Promise<TState | null> {
+    if (this.running) {
+      throw new Error('Cannot transition manually while state machine is running');
+    }
+    return this.execute(state);
+  }
+
+  private async execute(state: TState): Promise<TState | null> {
+    const handler = this.handlers.get(state);
+    if (!handler) {
+      throw new Error(`State is not registered: ${state}`);
+    }
+
+    const previous = this.currentState;
+    this.currentState = state;
+    this.onTransition?.({ from: previous, to: state });
+    return handler();
+  }
+}

+ 9 - 0
assets/scripts/framework/state/AsyncStateMachine.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "b1168396-0d15-4f2d-a2ac-70c219e4b968",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/framework/ui.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "a5ae997f-f076-462b-82e1-09bfb754eee6",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 36 - 0
assets/scripts/framework/ui/UILayer.ts

@@ -0,0 +1,36 @@
+export enum UILayer {
+  Page = 'Page',
+  Window = 'Window',
+  Popup = 'Popup',
+  Toast = 'Toast',
+  Loading = 'Loading',
+  System = 'System',
+}
+
+export enum UICachePolicy {
+  /** 不缓存 关闭立即销毁 */
+  None = 'none',
+  /** 关闭只隐藏 */
+  Persist = 'persist',
+  /** 延迟关闭, 5秒后不使用销毁 */
+  Delayed = 'delayed',
+}
+
+export enum UICloseReason {
+  User = 'user',
+  Navigation = 'navigation',
+  Logout = 'logout',
+  SceneChanged = 'scene-changed',
+  ForceDispose = 'force-dispose',
+}
+
+export enum UIViewState {
+  None,
+  Loading,
+  Creating,
+  Opening,
+  Opened,
+  Closing,
+  Cached,
+  Disposed,
+}

+ 9 - 0
assets/scripts/framework/ui/UILayer.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "0b38e1e2-26dc-4a72-9f25-5bcd0e744178",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 339 - 0
assets/scripts/framework/ui/UIManager.ts

@@ -0,0 +1,339 @@
+import { instantiate, Node } from 'cc';
+import { BUNDLE_ID } from '@scripts/define/ResDefine';
+import { getUIViewConfig, UIViewConfig, UIViewID } from '../../define/UIDefine';
+import { ResourceManager } from '../resource/ResourceManager';
+import { UICachePolicy, UICloseReason, UILayer, UIViewState } from './UILayer';
+import { UIView } from './UIView';
+
+interface UIViewRecord {
+  config: UIViewConfig;
+  state: UIViewState;
+  view: UIView | null;
+  ownerRoot: Node | null;
+  generation: number;
+  opening: Promise<UIView | null> | null;
+  closing: Promise<boolean> | null;
+  delayedDestroyTimer: ReturnType<typeof setTimeout> | null;
+}
+
+export class UIManager {
+  private static readonly DELAYED_DESTROY_MS = 5000;
+
+  private readonly records = new Map<UIViewID, UIViewRecord>();
+  private readonly roots = new Map<UILayer, Node>();
+
+  constructor(private readonly resources: ResourceManager) { }
+
+  bindLayer(layer: UILayer, root: Node): void {
+    this.roots.set(layer, root);
+  }
+
+  /**
+   * 接管当前场景各 UI Layer 中预放置的 UIView。
+   * 注册后的 View 先进入缓存态,之后仍由 open/close 统一驱动生命周期。
+   */
+  async registerSceneViews(): Promise<void> {
+    for (const [layer, root] of this.roots) {
+      if (!root.isValid) continue;
+
+      const views = root.getComponentsInChildren(UIView);
+      for (const view of views) {
+        const viewId = view.viewId;
+        if (!viewId) {
+          console.warn(`[UIManager] Scene UIView has no viewId: ${view.node.name}`);
+          continue;
+        }
+
+        const config = getUIViewConfig(viewId);
+        if (!config) {
+          console.warn(`[UIManager] Scene UIView is not configured: ${viewId}`);
+          continue;
+        }
+        if (config.layer !== layer) {
+          console.warn(
+            `[UIManager] Scene UIView is under the wrong layer: ${viewId}, expected=${config.layer}, actual=${layer}`,
+          );
+          continue;
+        }
+
+        const existing = this.records.get(viewId);
+        if (existing?.view === view) continue;
+        if (existing?.view?.node?.isValid) {
+          console.warn(`[UIManager] Duplicate scene UIView ignored: ${viewId}`);
+          continue;
+        }
+        if (existing) this.forgetRecord(existing);
+
+        const record: UIViewRecord = {
+          config,
+          state: UIViewState.Creating,
+          view,
+          ownerRoot: root,
+          generation: 1,
+          opening: null,
+          closing: null,
+          delayedDestroyTimer: null,
+        };
+        this.records.set(viewId, record);
+        view.node.active = false;
+
+        try {
+          await view.internalCreate();
+          if (!view.node.isValid || this.records.get(viewId) !== record) {
+            this.forgetRecord(record);
+            continue;
+          }
+          record.state = UIViewState.Cached;
+        } catch (error) {
+          this.forgetRecord(record);
+          throw error;
+        }
+      }
+    }
+  }
+
+  clearSceneLayers(): void {
+    const sceneRoots = new Set(this.roots.values());
+    this.roots.clear();
+
+    for (const record of [...this.records.values()]) {
+      const node = record.view?.node;
+      const belongsToSceneLayer = node?.isValid
+        ? [...sceneRoots].some((root) => root.isValid && (node === root || node.isChildOf(root)))
+        : record.ownerRoot !== null && sceneRoots.has(record.ownerRoot);
+
+      if (!node?.isValid || belongsToSceneLayer) {
+        this.forgetRecord(record);
+      }
+    }
+  }
+
+  get<TView extends UIView>(viewId: UIViewID): TView | null {
+    const record = this.records.get(viewId);
+    if (
+      !record
+      || !record.view?.node?.isValid
+      || (record.state !== UIViewState.Opening && record.state !== UIViewState.Opened)
+    ) {
+      return null;
+    }
+    return record.view as TView | null;
+  }
+
+  isOpen(viewId: UIViewID): boolean {
+    return this.get(viewId) !== null;
+  }
+
+  async open<TView extends UIView, TParams = unknown>(viewId: UIViewID, params?: TParams): Promise<TView | null> {
+    let record = this.records.get(viewId);
+    if (record?.view && !record.view.node.isValid) {
+      this.forgetRecord(record);
+      record = undefined;
+    }
+    if (record?.state === UIViewState.Opened) return record.view as TView;
+    if (record?.opening) return record.opening as Promise<TView | null>;
+    if (record?.closing) await record.closing;
+    if (record) this.cancelDelayedDestroy(record);
+
+    if (record?.state === UIViewState.Cached && record.view?.node.isValid) {
+      await this.closeMutexViews(record.config);
+      record.state = UIViewState.Opening;
+      record.view.node.active = true;
+      await record.view.internalOpen(params);
+      record.state = UIViewState.Opened;
+      return record.view as TView;
+    }
+
+    const config = getUIViewConfig(viewId);
+    const root = this.roots.get(config.layer);
+    if (!root?.isValid) throw new Error(`[UIManager] UILayer is not bound: ${config.layer}`);
+
+    record = record ?? {
+      config,
+      state: UIViewState.None,
+      view: null,
+      ownerRoot: root,
+      generation: 0,
+      opening: null,
+      closing: null,
+      delayedDestroyTimer: null,
+    };
+    record.ownerRoot = root;
+    this.records.set(viewId, record);
+
+    const generation = ++record.generation;
+    record.opening = this.performOpen(record, root, params, generation);
+    try {
+      return await record.opening as TView | null;
+    } finally {
+      if (record.generation === generation) record.opening = null;
+    }
+  }
+
+  async close(viewIdOrInstance: UIViewID, reason = UICloseReason.User): Promise<boolean> {
+    const record = typeof viewIdOrInstance === 'string'
+      ? this.records.get(viewIdOrInstance)
+      : [...this.records.values()].find((item) => item.view === viewIdOrInstance);
+    if (!record) return false;
+    if (record.closing) return record.closing;
+    if (record.state === UIViewState.Cached) return true;
+
+    ++record.generation;
+    record.closing = this.performClose(record, reason);
+    try {
+      return await record.closing;
+    } finally {
+      record.closing = null;
+    }
+  }
+
+  async closeAll(reason = UICloseReason.SceneChanged): Promise<void> {
+    await Promise.all([...this.records.values()].map((record) => this.close(record.config.id, reason)));
+  }
+
+  private async performOpen(
+    record: UIViewRecord,
+    root: Node,
+    params: unknown,
+    generation: number,
+  ): Promise<UIView | null> {
+    record.state = UIViewState.Loading;
+    const bundleName = record.config.bundle || BUNDLE_ID.Lobby;
+    const prefab = await this.resources.loadPrefab(bundleName, record.config.prefabPath);
+    if (generation !== record.generation) return null;
+
+    record.state = UIViewState.Creating;
+    const node = instantiate(prefab);
+    root.addChild(node);
+    const view = node.getComponent(UIView);
+    if (!view) {
+      node.destroy();
+      throw new Error(`[UIManager] Prefab has no UIView component: ${record.config.id}`);
+    }
+
+    record.view = view;
+    await view.internalCreate();
+    if (generation !== record.generation || !node.isValid) {
+      node.destroy();
+      record.view = null;
+      return null;
+    }
+
+    await this.closeMutexViews(record.config);
+    record.state = UIViewState.Opening;
+    node.active = true;
+    await view.internalOpen(params);
+    if (generation !== record.generation || !node.isValid) return null;
+
+    record.state = UIViewState.Opened;
+    return view;
+  }
+
+  private async performClose(record: UIViewRecord, reason: UICloseReason): Promise<boolean> {
+    if (!record.view?.node?.isValid) {
+      this.cancelDelayedDestroy(record);
+      record.state = UIViewState.Disposed;
+      record.view = null;
+      this.records.delete(record.config.id);
+      return false;
+    }
+
+    const allow = reason === UICloseReason.ForceDispose
+      ? true
+      : await record.view.internalBeforeClose(reason);
+    if (!allow) return false;
+
+    record.state = UIViewState.Closing;
+    await record.view.internalClose(reason);
+
+    const uiCache = record.config.cache || UICachePolicy.None;
+    if (reason === UICloseReason.ForceDispose || uiCache === UICachePolicy.None) {
+      this.disposeRecord(record);
+      return true;
+    }
+
+    record.view.node.active = false;
+    record.state = UIViewState.Cached;
+
+    if (uiCache === UICachePolicy.Delayed) {
+      this.scheduleDelayedDestroy(record);
+    }
+    return true;
+  }
+
+  private scheduleDelayedDestroy(record: UIViewRecord): void {
+    this.cancelDelayedDestroy(record);
+    const generation = record.generation;
+    record.delayedDestroyTimer = setTimeout(() => {
+      record.delayedDestroyTimer = null;
+      if (
+        record.generation === generation
+        && record.state === UIViewState.Cached
+      ) {
+        this.disposeRecord(record);
+      }
+    }, UIManager.DELAYED_DESTROY_MS);
+  }
+
+  private cancelDelayedDestroy(record: UIViewRecord): void {
+    if (record.delayedDestroyTimer === null) return;
+    clearTimeout(record.delayedDestroyTimer);
+    record.delayedDestroyTimer = null;
+  }
+
+  private disposeRecord(record: UIViewRecord): void {
+    this.cancelDelayedDestroy(record);
+    if (record.view?.node?.isValid) {
+      record.view.internalDispose();
+      record.view.node.destroy();
+    }
+    record.view = null;
+    record.ownerRoot = null;
+    record.state = UIViewState.Disposed;
+    this.records.delete(record.config.id);
+  }
+
+  /** 从管理器中同步移除记录,不主动销毁正由场景释放的节点。 */
+  private forgetRecord(record: UIViewRecord): void {
+    ++record.generation;
+    this.cancelDelayedDestroy(record);
+    if (record.view?.node?.isValid) {
+      record.view.internalDispose();
+    }
+    record.view = null;
+    record.ownerRoot = null;
+    record.opening = null;
+    record.closing = null;
+    record.state = UIViewState.Disposed;
+    if (this.records.get(record.config.id) === record) {
+      this.records.delete(record.config.id);
+    }
+  }
+
+  private async closeMutexViews(config: UIViewConfig): Promise<void> {
+    const tasks: Promise<boolean>[] = [];
+    for (const record of this.records.values()) {
+      if (!record.config.mutexGroup) continue;
+      if (record.config.id !== config.id && record.config.mutexGroup === config.mutexGroup) {
+        tasks.push(this.close(record.config.id, UICloseReason.Navigation));
+      }
+    }
+    await Promise.all(tasks);
+  }
+
+  loading(active: boolean) {
+    if (active) {
+      this.open(UIViewID.LoadingView);
+    } else {
+      this.close(UIViewID.LoadingView);
+    }
+  }
+
+  toast() {
+
+  }
+
+  dialog() {
+
+  }
+}

+ 9 - 0
assets/scripts/framework/ui/UIManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "15aa04ee-f9e0-4ef3-bf95-8ea71c4877fe",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 45 - 0
assets/scripts/framework/ui/UIView.ts

@@ -0,0 +1,45 @@
+import { _decorator, Component } from 'cc';
+import { UICloseReason } from './UILayer';
+import { AppKernel } from '../../app/AppKernel';
+import type { UIViewID } from '../../define/UIDefine';
+
+const { ccclass } = _decorator;
+
+@ccclass('UIView')
+export class UIView<TParams = unknown> extends Component {
+  /** UIManager 用它识别并接管场景中预放置的 UIView。 */
+  readonly viewId: UIViewID | null = null;
+
+  async internalCreate(): Promise<void> {
+    await this.onCreate();
+  }
+
+  async internalOpen(params: TParams): Promise<void> {
+    this.node.setSiblingIndex
+    await this.onOpen(params);
+  }
+
+  async internalBeforeClose(reason: UICloseReason): Promise<boolean> {
+    return this.onBeforeClose(reason);
+  }
+
+  async internalClose(reason: UICloseReason): Promise<void> {
+    await this.onClose(reason);
+  }
+
+  internalDispose(): void {
+    this.onDispose();
+  }
+
+  protected onDestroy(): void {
+    AppKernel.events.offTarget(this);
+  }
+
+  protected onCreate(): void | Promise<void> { }
+  protected onOpen(_params: TParams): void | Promise<void> { }
+  protected onFocus(): void { }
+  protected onBlur(): void { }
+  protected onBeforeClose(_reason: UICloseReason): boolean | Promise<boolean> { return true; }
+  protected onClose(_reason: UICloseReason): void | Promise<void> { }
+  protected onDispose(): void { }
+}

+ 9 - 0
assets/scripts/framework/ui/UIView.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "3feab0ee-064d-459e-baa9-bbe55ecfaf89",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/modules.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "bc51ca95-6c04-4f91-a3c4-d2f25389939b",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/modules/game.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "a9e187dd-ae79-45ae-afb2-785a116c9ec0",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 71 - 0
assets/scripts/modules/game/GameController.ts

@@ -0,0 +1,71 @@
+import { _decorator, Component, EventKeyboard, input, Input, KeyCode, Node, WebView } from 'cc';
+import { AppKernel } from '../../app/AppKernel';
+import AppConfig from '@scripts/app/AppConfig';
+import { ANDROID, IOS } from 'cc/env';
+import { getUrlParams } from '@scripts/utils/Helper';
+import { WebViewHandler } from './WebViewHandler';
+
+const { ccclass, property } = _decorator;
+
+interface IFrameEvent {
+  cmd?: string;
+  [key: string]: string | undefined;
+}
+
+const GAME_FRAME = "http://192.168.1.3:3001";
+
+@ccclass('GameController')
+export class GameController extends Component {
+
+  @property(WebView)
+  webView: WebView | null = null;
+
+  @property(Node)
+  loadingNode: Node | null = null;
+
+  private _gameWeb: WebViewHandler | null = null;
+
+  protected start(): void {
+    if (!this.webView) {
+      console.error('[GameController] WebView is not assigned.');
+      return;
+    }
+
+    this._gameWeb = new WebViewHandler(
+      this.webView,
+      GAME_FRAME,
+      this as any,
+      AppConfig.GameScheme
+    )
+
+    AppKernel.services.gameService.onEntered();
+  }
+
+  protected onDestroy(): void {
+    this._gameWeb?.clear();
+    this._gameWeb = null;
+    AppKernel.services.gameService.onExited();
+  }
+
+  onHandleMsg(data: IFrameEvent) {
+    console.log(">>>>>>>>>>>> handleWebEvent: ", data);
+    switch (data.cmd) {
+      case "game_ready":
+        const game_url = AppKernel.stores.mainStore.gameLink;
+        if (!this._gameWeb) {
+          console.warn('[GameController] Ignored game_ready after WebView disposal.');
+          return;
+        }
+        this._gameWeb.sendMessage({ cmd: "update_gamelink", url: game_url })
+        break;
+      case "game_exit":
+        this.exitGame();
+        break;
+    }
+  }
+
+  async exitGame(): Promise<void> {
+    await AppKernel.services.gameService.exitGame();
+  }
+
+}

+ 9 - 0
assets/scripts/modules/game/GameController.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "8f712da8-2733-4a6a-b5e3-41a1869f42ac",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 110 - 0
assets/scripts/modules/game/WebViewHandler.ts

@@ -0,0 +1,110 @@
+import { WebView } from "cc";
+import { ANDROID, IOS } from "cc/env";
+
+const HISTORY_STATE_KEY = '__game_webview_locked__';
+
+export interface IWebViewMsg {
+    cmd: string;
+    url?: string;
+}
+
+export interface IWebEventHandler {
+    onWebLoaded?: () => void,
+    onWebLoading?: () => void,
+    onWebError?: () => void,
+    onHandleMsg?: (data: IWebViewMsg) => void;
+}
+
+export class WebViewHandler {
+    private disposed = false;
+
+    constructor(private readonly webView: WebView,
+        private readonly url: string,
+        private readonly eventer: IWebEventHandler,
+        scheme: string) {
+        if (ANDROID || IOS) {
+            this.webView.setJavascriptInterfaceScheme(scheme);
+            //@ts-ignore
+            this.webView.setOnJSCallback(this.onSchemeCallback);
+            url = `${url}?scheme=${scheme}`;
+        }
+        this.webView.url = url;
+
+
+        webView.node.on(WebView.EventType.LOADED, this.onWebViewLoaded, this);
+        webView.node.on(WebView.EventType.LOADING, this.onWebViewLoading, this);
+        webView.node.on(WebView.EventType.ERROR, this.onWebViewError, this);
+
+        window?.addEventListener('message', this.onWindowMessage);
+        window?.addEventListener('popstate', this.onBrowserBack);
+        window?.history?.pushState(
+            { ...window.history.state, [HISTORY_STATE_KEY]: true },
+            '',
+            window.location.href,
+        );
+    }
+
+    public clear() {
+        if (this.disposed) return;
+        this.disposed = true;
+
+        this.webView?.node.off(WebView.EventType.LOADED, this.onWebViewLoaded, this);
+        this.webView?.node.off(WebView.EventType.LOADING, this.onWebViewLoading, this);
+        this.webView?.node.off(WebView.EventType.ERROR, this.onWebViewError, this);
+
+        window?.removeEventListener('message', this.onWindowMessage);
+        window?.removeEventListener('popstate', this.onBrowserBack);
+    }
+
+    public sendMessage(message: IWebViewMsg) {
+        if (this.disposed || !this.webView?.isValid || !this.webView.node?.isValid) return;
+
+        if (ANDROID || IOS) {
+            const payload = JSON.stringify(message);
+            this.webView?.evaluateJS(`
+            (() => {     
+              const message = ${payload};         
+              window.postMessage(message, '*');
+            })();
+          `);
+        } else {
+            const iframe = this.webView?.nativeWebView;
+            iframe?.contentWindow?.postMessage(message, '*');
+        }
+    }
+
+    private onWebViewLoaded() {
+        this.eventer.onWebLoaded && this.eventer.onWebLoaded();
+    }
+
+    private onWebViewLoading() {
+        this.eventer.onWebLoading && this.eventer.onWebLoading();
+    }
+
+    private onWebViewError() {
+        this.eventer.onWebError && this.eventer.onWebError();
+    }
+
+    private readonly onBrowserBack = (): void => {
+        if (!this.webView.isValid || typeof window === 'undefined') return;
+
+        // 浏览器的返回无法被取消,因此立即补回当前游戏页历史记录。
+        window.history?.pushState(
+            { ...window.history.state, [HISTORY_STATE_KEY]: true },
+            '',
+            window.location.href,
+        );
+    };
+
+    private readonly onWindowMessage = (event: MessageEvent): void => {
+        if (this.disposed) return;
+        if (event.origin !== this.url) return;
+        this.handleWebEvent(event?.data);
+    };
+
+    private handleWebEvent(data: IWebViewMsg) {
+        if (!!data.cmd) {
+            this.eventer.onHandleMsg && this.eventer.onHandleMsg(data);
+        }
+    }
+}

+ 9 - 0
assets/scripts/modules/game/WebViewHandler.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "2798f2f7-fe90-4ed4-bcac-37da1b0b8530",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/modules/launch.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "a19dd9e7-32cc-4585-88df-c44d98bb344c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 163 - 0
assets/scripts/modules/launch/LaunchController.ts

@@ -0,0 +1,163 @@
+import {
+  _decorator,
+  BlockInputEvents,
+  Button,
+  Camera,
+  Canvas,
+  Component,
+  director,
+  Director,
+  Label,
+  Node,
+  ProgressBar,
+} from 'cc';
+import { AppKernel } from '../../app/AppKernel';
+import { LaunchProgress, LaunchStateMachine } from './LaunchStateMachine';
+import { LaunchDialog } from './states/LaunchState';
+
+const { ccclass, property } = _decorator;
+
+@ccclass('LaunchController')
+export class LaunchController extends Component {
+  @property(Canvas)
+  canvas: Canvas | null = null;
+
+  @property(Label)
+  progressLabel: Label | null = null;
+
+  @property(ProgressBar)
+  progressBar: ProgressBar | null = null;
+
+  @property(Node)
+  dialogNode: Node | null = null;
+
+  @property(Label)
+  dialogLabel: Label | null = null;
+
+  @property(Button)
+  dialogConfirmButton: Button | null = null;
+
+  @property(Button)
+  dialogCancelButton: Button | null = null;
+
+  private launchStateMachine: LaunchStateMachine | null = null;
+  private dialogResolve: ((confirmed: boolean) => void) | null = null;
+
+  protected onLoad(): void {
+    director.addPersistRootNode(this.node);
+
+    AppKernel.initialize();
+    this.initEvents();
+    this.launchStateMachine = new LaunchStateMachine({
+      kernel: AppKernel.Instance,
+      error: null,
+      progress: (value) => this.updateProgress(value),
+      dialog: (message) => this.showDialog(message),
+    });
+  }
+
+  private initEvents(): void {
+    director.on(Director.EVENT_AFTER_SCENE_LAUNCH, this.onChangeScene, this,);
+    AppKernel.events.once('launch:completed', this.onLaunchCompleted, this);
+  }
+
+  private onLaunchCompleted(): void {
+    if (!this.node.isValid) return;
+
+    this.node.active = false;
+    if (director.isPersistRootNode(this.node)) {
+      director.removePersistRootNode(this.node);
+    }
+    this.node.destroy();
+  }
+
+  protected async start(): Promise<void> {
+    await this.launchStateMachine?.run();
+  }
+
+  protected onDestroy(): void {
+    this.finishDialog(false);
+    AppKernel.events.offTarget(this);
+    director.off(Director.EVENT_AFTER_SCENE_LAUNCH, this.onChangeScene, this);
+  }
+
+  private readonly onChangeScene = (): void => {
+    if (!this.node.isValid) return;
+
+    const scene = director.getScene();
+    const lobbyCanvas = scene?.getComponentsInChildren(Canvas)?.find(item => item != this.canvas);
+    this.canvas.enabled = false;
+    if (lobbyCanvas) {
+      this.node.setParent(lobbyCanvas.node, true);
+      this.node.setSiblingIndex(lobbyCanvas.node.children.length - 1);
+    }
+  };
+
+  private updateProgress(value: LaunchProgress): void {
+    if (value.title !== undefined && this.progressLabel) {
+      this.progressLabel.string = value.title;
+    }
+    if (value.progress !== undefined && this.progressBar) {
+      this.progressBar.progress = value.progress;
+    }
+  }
+
+  private showDialog({ message }: LaunchDialog): Promise<boolean> {
+    if (
+      !this.dialogNode
+      || !this.dialogLabel
+      || !this.dialogConfirmButton
+      || !this.dialogCancelButton
+    ) {
+      if (typeof globalThis.confirm === 'function') {
+        return Promise.resolve(globalThis.confirm(message));
+      }
+      console.warn('[LaunchController] dialog nodes are not configured');
+      return Promise.resolve(false);
+    }
+
+    this.finishDialog(false);
+    this.dialogLabel.string = message;
+    this.dialogNode.active = true;
+
+    return new Promise<boolean>((resolve) => {
+      this.dialogResolve = resolve;
+      this.dialogConfirmButton?.node.once(
+        Button.EventType.CLICK,
+        this.onDialogConfirm,
+        this,
+      );
+      this.dialogCancelButton?.node.once(
+        Button.EventType.CLICK,
+        this.onDialogCancel,
+        this,
+      );
+    });
+  }
+
+  private readonly onDialogConfirm = (): void => {
+    this.finishDialog(true);
+  };
+
+  private readonly onDialogCancel = (): void => {
+    this.finishDialog(false);
+  };
+
+  private finishDialog(confirmed: boolean): void {
+    this.dialogConfirmButton?.node.off(
+      Button.EventType.CLICK,
+      this.onDialogConfirm,
+      this,
+    );
+    this.dialogCancelButton?.node.off(
+      Button.EventType.CLICK,
+      this.onDialogCancel,
+      this,
+    );
+    if (this.dialogNode) this.dialogNode.active = false;
+
+    const resolve = this.dialogResolve;
+    this.dialogResolve = null;
+    resolve?.(confirmed);
+  }
+}

+ 9 - 0
assets/scripts/modules/launch/LaunchController.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "4a90a445-7d72-4141-af90-bd22771b2e19",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 59 - 0
assets/scripts/modules/launch/LaunchStateMachine.ts

@@ -0,0 +1,59 @@
+import { AppKernel } from '../../app/AppKernel';
+import { AsyncStateMachine } from '../../framework/state/AsyncStateMachine';
+import { CheckVersionState } from './states/CheckVersionState';
+import { CompleteState } from './states/CompleteState';
+import { EnterLobbyState } from './states/EnterLobbyState';
+import { FailedState } from './states/FailedState';
+import { HotUpdateState } from './states/HotUpdateState';
+import {
+  LaunchContext,
+  LaunchProgress,
+  LaunchState,
+  LaunchStateId,
+} from './states/LaunchState';
+import { PreloadLobbyState } from './states/PreloadLobbyState';
+
+export type { LaunchProgress } from './states/LaunchState';
+
+export type LaunchProgressHandler = (value: LaunchProgress) => void;
+
+/**
+ * 启动业务状态机。
+ *
+ * 负责版本检测、热更新、资源预加载、场景切换和统一失败处理,
+ */
+export class LaunchStateMachine {
+  private readonly machine = new AsyncStateMachine<LaunchStateId>();
+
+  constructor(private readonly context: LaunchContext) {
+    this.registerStates();
+  }
+
+  get current(): LaunchStateId | null {
+    return this.machine.current;
+  }
+
+  async run(): Promise<void> {
+    try {
+      await this.machine.start(LaunchStateId.CheckVersion);
+    } catch (error) {
+      this.context.error = error;
+      await this.machine.transition(LaunchStateId.Failed);
+    }
+  }
+
+  private registerStates(): void {
+    const states: LaunchState[] = [
+      new CheckVersionState(),
+      new HotUpdateState(),
+      new PreloadLobbyState(),
+      new EnterLobbyState(),
+      new CompleteState(),
+      new FailedState(),
+    ];
+
+    for (const state of states) {
+      this.machine.register(state.id, () => state.enter(this.context));
+    }
+  }
+}

+ 9 - 0
assets/scripts/modules/launch/LaunchStateMachine.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "57024e17-ef66-4820-bb58-b1a55a3d7a28",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/modules/launch/states.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "d0970a6b-363d-4b09-a6b2-5fd5d419590d",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 12 - 0
assets/scripts/modules/launch/states/CheckVersionState.ts

@@ -0,0 +1,12 @@
+import { LaunchContext, LaunchState, LaunchStateId } from './LaunchState';
+
+export class CheckVersionState implements LaunchState {
+  readonly id = LaunchStateId.CheckVersion;
+
+  async enter(context: LaunchContext): Promise<LaunchStateId> {
+    context.progress({ state: this.id, title: '检查版本' });
+    await context.kernel.version.check();
+    context.progress({ state: this.id, progress: 0.25 });
+    return LaunchStateId.HotUpdate;
+  }
+}

Vissa filer visades inte eftersom för många filer har ändrats