From 8cf1a2b30d19eb4e9b79a39a5da346f31b0e814d Mon Sep 17 00:00:00 2001 From: wuyanchen <307378529@qq.com> Date: Tue, 23 Dec 2025 16:42:04 +0800 Subject: [PATCH] =?UTF-8?q?=C2=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../script/manager/ColyseusManager.ts | 10 +- .../crazystudio/script/manager/GameManager.ts | 31 +- build-templates/wechatgame/game.ejs | 14 +- .../wechatgame/lib/es6-promise.auto.js | 3 + build-templates/wechatgame/lib/es6-promise.js | 7 + .../wechatgame/lib/es6-promise/-internal.js | 243 ++++++++++ .../wechatgame/lib/es6-promise/asap.js | 119 +++++ .../wechatgame/lib/es6-promise/enumerator.js | 124 +++++ .../wechatgame/lib/es6-promise/polyfill.js | 35 ++ .../wechatgame/lib/es6-promise/promise.js | 431 ++++++++++++++++++ .../wechatgame/lib/es6-promise/promise/all.js | 52 +++ .../lib/es6-promise/promise/race.js | 84 ++++ .../lib/es6-promise/promise/reject.js | 46 ++ .../lib/es6-promise/promise/resolve.js | 48 ++ .../wechatgame/lib/es6-promise/then.js | 32 ++ .../wechatgame/lib/es6-promise/utils.js | 21 + build-templates/wechatgame/lib/fix-symbol.js | 66 +++ .../runtime/colyseus.js | 18 +- .../runtime/colyseus.js | 18 +- package-lock.json | 9 +- package.json | 2 +- tsconfig.json | 25 +- 22 files changed, 1374 insertions(+), 64 deletions(-) create mode 100644 build-templates/wechatgame/lib/es6-promise.auto.js create mode 100644 build-templates/wechatgame/lib/es6-promise.js create mode 100644 build-templates/wechatgame/lib/es6-promise/-internal.js create mode 100644 build-templates/wechatgame/lib/es6-promise/asap.js create mode 100644 build-templates/wechatgame/lib/es6-promise/enumerator.js create mode 100644 build-templates/wechatgame/lib/es6-promise/polyfill.js create mode 100644 build-templates/wechatgame/lib/es6-promise/promise.js create mode 100644 build-templates/wechatgame/lib/es6-promise/promise/all.js create mode 100644 build-templates/wechatgame/lib/es6-promise/promise/race.js create mode 100644 build-templates/wechatgame/lib/es6-promise/promise/reject.js create mode 100644 build-templates/wechatgame/lib/es6-promise/promise/resolve.js create mode 100644 build-templates/wechatgame/lib/es6-promise/then.js create mode 100644 build-templates/wechatgame/lib/es6-promise/utils.js create mode 100644 build-templates/wechatgame/lib/fix-symbol.js diff --git a/assets/crazystudio/script/manager/ColyseusManager.ts b/assets/crazystudio/script/manager/ColyseusManager.ts index 29e0b39..0d8b252 100644 --- a/assets/crazystudio/script/manager/ColyseusManager.ts +++ b/assets/crazystudio/script/manager/ColyseusManager.ts @@ -1,5 +1,12 @@ + +// import "core-js"; +import "core-js/actual/url/index.js"; +import "core-js/actual/url-search-params/index.js"; + import { _decorator, Component, director, Game, game, v3, Vec3 } from "cc"; +// import "url-polyfill"; + // 据报道,微信的JavaScript运行时不支持通过WebSocket直接发送或数据类型。为了绕过这个问题,你可以对这些数据类型进行猴子补丁,将这些数据类型转换成微信能处理的格式。Uint8ArrayArrayWebSocket.send const WebSocket_send = WebSocket.prototype.send; @@ -13,8 +20,6 @@ WebSocket.prototype.send = function (data) { } }; - - import Colyseus, { RoomAvailable } from "db://colyseus-sdk/colyseus.js"; import { XNetEventKeys } from "../net/XNetEventKeys"; import { Global } from "../Global"; @@ -31,7 +36,6 @@ import { PlayerTool } from "../player/PlayerTool"; import { WebNetLogic } from "../net/WebNetLogic"; const { encode, decode } = msgpackpure; - @ccclass("ColyseusManager") export class ColyseusManager extends Component { @property hostname = "localhost"; diff --git a/assets/crazystudio/script/manager/GameManager.ts b/assets/crazystudio/script/manager/GameManager.ts index b98f164..914e2dd 100644 --- a/assets/crazystudio/script/manager/GameManager.ts +++ b/assets/crazystudio/script/manager/GameManager.ts @@ -1,29 +1,18 @@ -import 'core-js/actual/url/index.js' -import 'core-js/actual/url-search-params/index.js' -import { _decorator, Component, director } from 'cc'; +import { _decorator, Component, director } from "cc"; const { ccclass, property } = _decorator; -@ccclass('GameManager') +@ccclass("GameManager") export class GameManager extends Component { + protected onLoad(): void {} + start() { + // const colyseusManager = director.getScene().getComponentInChildren(ColyseusManager) + // console.log('GameManager start') + // WebNetLogic.init() + } + // update(deltaTime: number) { - protected onLoad(): void { - } - - - - start() { - - // const colyseusManager = director.getScene().getComponentInChildren(ColyseusManager) - // console.log('GameManager start') - // WebNetLogic.init() - } - - // update(deltaTime: number) { - - // } + // } } - - diff --git a/build-templates/wechatgame/game.ejs b/build-templates/wechatgame/game.ejs index a2c803d..96722c0 100644 --- a/build-templates/wechatgame/game.ejs +++ b/build-templates/wechatgame/game.ejs @@ -1,17 +1,19 @@ +require('./lib/fix-symbol.js'); + function __initApp () { // init app + + globalThis.__wxRequire = require; // FIX: require cannot work in separate engine require('./web-adapter'); + + + const firstScreen = require('./first-screen'); require("./lib/EncoderDecoderTogether.min.js"); require('./lib/fetch.js') +require('./lib/es6-promise.js').default.polyfill(); -//解决:Colyseus 无法将函数“class ReflectionField扩展模式#160”的属性“Symbol(Symbol.metadata)”分配为只读。的问题 -Object.defineProperty(Function.prototype, Symbol.metadata, { - value: null, - writable: true, - configurable: true, -}); <%- include(cocosTemplate, {}) %> diff --git a/build-templates/wechatgame/lib/es6-promise.auto.js b/build-templates/wechatgame/lib/es6-promise.auto.js new file mode 100644 index 0000000..7799786 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise.auto.js @@ -0,0 +1,3 @@ +import Promise from './es6-promise'; +Promise.polyfill(); +export default Promise; diff --git a/build-templates/wechatgame/lib/es6-promise.js b/build-templates/wechatgame/lib/es6-promise.js new file mode 100644 index 0000000..4f4d840 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise.js @@ -0,0 +1,7 @@ +import Promise from './es6-promise/promise'; +import polyfill from './es6-promise/polyfill'; + +// Strange compat.. +Promise.polyfill = polyfill; +Promise.Promise = Promise; +export default Promise; diff --git a/build-templates/wechatgame/lib/es6-promise/-internal.js b/build-templates/wechatgame/lib/es6-promise/-internal.js new file mode 100644 index 0000000..6bd75a8 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/-internal.js @@ -0,0 +1,243 @@ +import { + objectOrFunction, + isFunction +} from './utils'; + +import { + asap +} from './asap'; + +import originalThen from './then'; +import originalResolve from './promise/resolve'; + +export const PROMISE_ID = Math.random().toString(36).substring(2); + +function noop() {} + +const PENDING = void 0; +const FULFILLED = 1; +const REJECTED = 2; + +function selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); +} + +function cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); +} + +function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } +} + +function handleForeignThenable(promise, thenable, then) { + asap(promise => { + let sealed = false; + let error = tryThen(then, thenable, value => { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, reason => { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); +} + +function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (thenable._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, value => resolve(promise, value), + reason => reject(promise, reason)) + } +} + +function handleMaybeThenable(promise, maybeThenable, then) { + if (maybeThenable.constructor === promise.constructor && + then === originalThen && + maybeThenable.constructor.resolve === originalResolve) { + handleOwnThenable(promise, maybeThenable); + } else { + if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } +} + +function resolve(promise, value) { + if (promise === value) { + reject(promise, selfFulfillment()); + } else if (objectOrFunction(value)) { + let then; + try { + then = value.then; + } catch (error) { + reject(promise, error); + return; + } + handleMaybeThenable(promise, value, then); + } else { + fulfill(promise, value); + } +} + +function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); +} + +function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length !== 0) { + asap(publish, promise); + } +} + +function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + asap(publishRejection, promise); +} + +function subscribe(parent, child, onFulfillment, onRejection) { + let { _subscribers } = parent; + let { length } = _subscribers; + + parent._onerror = null; + + _subscribers[length] = child; + _subscribers[length + FULFILLED] = onFulfillment; + _subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + asap(publish, parent); + } +} + +function publish(promise) { + let subscribers = promise._subscribers; + let settled = promise._state; + + if (subscribers.length === 0) { return; } + + let child, callback, detail = promise._result; + + for (let i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; +} + +function invokeCallback(settled, promise, callback, detail) { + let hasCallback = isFunction(callback), + value, error, succeeded = true; + + if (hasCallback) { + try { + value = callback(detail); + } catch (e) { + succeeded = false; + error = e; + } + + if (promise === value) { + reject(promise, cannotReturnOwn()); + return; + } + } else { + value = detail; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (succeeded === false) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } +} + +function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } +} + +let id = 0; +function nextId() { + return id++; +} + +function makePromise(promise) { + promise[PROMISE_ID] = id++; + promise._state = undefined; + promise._result = undefined; + promise._subscribers = []; +} + +export { + nextId, + makePromise, + noop, + resolve, + reject, + fulfill, + subscribe, + publish, + publishRejection, + initializePromise, + invokeCallback, + FULFILLED, + REJECTED, + PENDING, + handleMaybeThenable +}; diff --git a/build-templates/wechatgame/lib/es6-promise/asap.js b/build-templates/wechatgame/lib/es6-promise/asap.js new file mode 100644 index 0000000..56d5ebb --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/asap.js @@ -0,0 +1,119 @@ +let len = 0; +let vertxNext; +let customSchedulerFn; + +export var asap = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (customSchedulerFn) { + customSchedulerFn(flush); + } else { + scheduleFlush(); + } + } +} + +export function setScheduler(scheduleFn) { + customSchedulerFn = scheduleFn; +} + +export function setAsap(asapFn) { + asap = asapFn; +} + +const browserWindow = (typeof window !== 'undefined') ? window : undefined; +const browserGlobal = browserWindow || {}; +const BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; +const isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; + +// test for web worker but not in IE10 +const isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + +// node +function useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return () => process.nextTick(flush); +} + +// vertx +function useVertxTimer() { + if (typeof vertxNext !== 'undefined') { + return function() { + vertxNext(flush); + }; + } + + return useSetTimeout(); +} + +function useMutationObserver() { + let iterations = 0; + const observer = new BrowserMutationObserver(flush); + const node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return () => { + node.data = (iterations = ++iterations % 2); + }; +} + +// web worker +function useMessageChannel() { + const channel = new MessageChannel(); + channel.port1.onmessage = flush; + return () => channel.port2.postMessage(0); +} + +function useSetTimeout() { + // Store setTimeout reference so es6-promise will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + const globalSetTimeout = setTimeout; + return () => globalSetTimeout(flush, 0); +} + +const queue = new Array(1000); +function flush() { + for (let i = 0; i < len; i+=2) { + let callback = queue[i]; + let arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; +} + +function attemptVertx() { + try { + const vertx = Function('return this')().require('vertx'); + vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch(e) { + return useSetTimeout(); + } +} + +let scheduleFlush; +// Decide what async method to use to triggering processing of queued callbacks: +if (isNode) { + scheduleFlush = useNextTick(); +} else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); +} else if (isWorker) { + scheduleFlush = useMessageChannel(); +} else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertx(); +} else { + scheduleFlush = useSetTimeout(); +} diff --git a/build-templates/wechatgame/lib/es6-promise/enumerator.js b/build-templates/wechatgame/lib/es6-promise/enumerator.js new file mode 100644 index 0000000..be2e093 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/enumerator.js @@ -0,0 +1,124 @@ +import { + isArray, + isMaybeThenable +} from './utils'; +import { + noop, + reject, + fulfill, + subscribe, + FULFILLED, + REJECTED, + PENDING, + handleMaybeThenable +} from './-internal'; + +import then from './then'; +import Promise from './promise'; +import originalResolve from './promise/resolve'; +import originalThen from './then'; +import { makePromise, PROMISE_ID } from './-internal'; + +function validationError() { + return new Error('Array Methods must be provided an Array'); +}; + +export default class Enumerator { + constructor(Constructor, input) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop); + + if (!this.promise[PROMISE_ID]) { + makePromise(this.promise); + } + + if (isArray(input)) { + this.length = input.length; + this._remaining = input.length; + + this._result = new Array(this.length); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(input); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, validationError()); + } + } + _enumerate(input) { + for (let i = 0; this._state === PENDING && i < input.length; i++) { + this._eachEntry(input[i], i); + } + } + + _eachEntry(entry, i) { + let c = this._instanceConstructor; + let { resolve } = c; + + if (resolve === originalResolve) { + let then; + let error; + let didError = false; + try { + then = entry.then; + } catch (e) { + didError = true; + error = e; + } + + if (then === originalThen && + entry._state !== PENDING) { + this._settledAt(entry._state, i, entry._result); + } else if (typeof then !== 'function') { + this._remaining--; + this._result[i] = entry; + } else if (c === Promise) { + let promise = new c(noop); + if (didError) { + reject(promise, error); + } else { + handleMaybeThenable(promise, entry, then); + } + this._willSettleAt(promise, i); + } else { + this._willSettleAt(new c(resolve => resolve(entry)), i); + } + } else { + this._willSettleAt(resolve(entry), i); + } + } + + _settledAt(state, i, value) { + let { promise } = this; + + if (promise._state === PENDING) { + this._remaining--; + + if (state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = value; + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + } + + _willSettleAt(promise, i) { + let enumerator = this; + + subscribe( + promise, undefined, + value => enumerator._settledAt(FULFILLED, i, value), + reason => enumerator._settledAt(REJECTED, i, reason) + ); + } +}; diff --git a/build-templates/wechatgame/lib/es6-promise/polyfill.js b/build-templates/wechatgame/lib/es6-promise/polyfill.js new file mode 100644 index 0000000..30db73c --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/polyfill.js @@ -0,0 +1,35 @@ +/*global self*/ +import Promise from './promise'; + +export default function polyfill() { + let local; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + let P = local.Promise; + + if (P) { + var promiseToString = null; + try { + promiseToString = Object.prototype.toString.call(P.resolve()); + } catch(e) { + // silently ignored + } + + if (promiseToString === '[object Promise]' && !P.cast){ + return; + } + } + + local.Promise = Promise; +} diff --git a/build-templates/wechatgame/lib/es6-promise/promise.js b/build-templates/wechatgame/lib/es6-promise/promise.js new file mode 100644 index 0000000..ae17036 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/promise.js @@ -0,0 +1,431 @@ +import { + isFunction +} from './utils'; +import { + noop, + nextId, + PROMISE_ID, + initializePromise +} from './-internal'; +import { + asap, + setAsap, + setScheduler +} from './asap'; + +import all from './promise/all'; +import race from './promise/race'; +import Resolve from './promise/resolve'; +import Reject from './promise/reject'; +import then from './then'; + +function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); +} + +function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); +} + +/** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + let promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {Function} resolver + Useful for tooling. + @constructor +*/ + +class Promise { + constructor(resolver) { + this[PROMISE_ID] = nextId(); + this._result = this._state = undefined; + this._subscribers = []; + + if (noop !== resolver) { + typeof resolver !== 'function' && needsResolver(); + this instanceof Promise ? initializePromise(this, resolver) : needsNew(); + } + } + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + let result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + let author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + catch(onRejection) { + return this.then(null, onRejection); + } + +/** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @return {Promise} +*/ + finally(callback) { + let promise = this; + let constructor = promise.constructor; + + if ( isFunction(callback) ) { + return promise.then(value => constructor.resolve(callback()).then(() => value), + reason => constructor.resolve(callback()).then(() => { throw reason; })); + } + + return promise.then(callback, callback); + } +} + +Promise.prototype.then = then; +export default Promise; +Promise.all = all; +Promise.race = race; +Promise.resolve = Resolve; +Promise.reject = Reject; +Promise._setScheduler = setScheduler; +Promise._setAsap = setAsap; +Promise._asap = asap; + diff --git a/build-templates/wechatgame/lib/es6-promise/promise/all.js b/build-templates/wechatgame/lib/es6-promise/promise/all.js new file mode 100644 index 0000000..9ca3c06 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/promise/all.js @@ -0,0 +1,52 @@ +import Enumerator from '../enumerator'; + +/** + `Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = resolve(2); + let promise3 = resolve(3); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + let promise1 = resolve(1); + let promise2 = reject(new Error("2")); + let promise3 = reject(new Error("3")); + let promises = [ promise1, promise2, promise3 ]; + + Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static +*/ +export default function all(entries) { + return new Enumerator(this, entries).promise; +} diff --git a/build-templates/wechatgame/lib/es6-promise/promise/race.js b/build-templates/wechatgame/lib/es6-promise/promise/race.js new file mode 100644 index 0000000..166dc82 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/promise/race.js @@ -0,0 +1,84 @@ +import { + isArray +} from "../utils"; + +/** + `Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + let promise1 = new Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + let promise2 = new Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. +*/ +export default function race(entries) { + /*jshint validthis:true */ + let Constructor = this; + + if (!isArray(entries)) { + return new Constructor((_, reject) => reject(new TypeError('You must pass an array to race.'))); + } else { + return new Constructor((resolve, reject) => { + let length = entries.length; + for (let i = 0; i < length; i++) { + Constructor.resolve(entries[i]).then(resolve, reject); + } + }); + } +} diff --git a/build-templates/wechatgame/lib/es6-promise/promise/reject.js b/build-templates/wechatgame/lib/es6-promise/promise/reject.js new file mode 100644 index 0000000..cd55faa --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/promise/reject.js @@ -0,0 +1,46 @@ +import { + noop, + reject as _reject +} from '../-internal'; + +/** + `Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. +*/ +export default function reject(reason) { + /*jshint validthis:true */ + let Constructor = this; + let promise = new Constructor(noop); + _reject(promise, reason); + return promise; +} diff --git a/build-templates/wechatgame/lib/es6-promise/promise/resolve.js b/build-templates/wechatgame/lib/es6-promise/promise/resolve.js new file mode 100644 index 0000000..f4642b6 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/promise/resolve.js @@ -0,0 +1,48 @@ +import { + noop, + resolve as _resolve +} from '../-internal'; + +/** + `Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + let promise = new Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + let promise = Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` +*/ +export default function resolve(object) { + /*jshint validthis:true */ + let Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + let promise = new Constructor(noop); + _resolve(promise, object); + return promise; +} diff --git a/build-templates/wechatgame/lib/es6-promise/then.js b/build-templates/wechatgame/lib/es6-promise/then.js new file mode 100644 index 0000000..b2b79f0 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/then.js @@ -0,0 +1,32 @@ +import { + invokeCallback, + subscribe, + FULFILLED, + REJECTED, + noop, + makePromise, + PROMISE_ID +} from './-internal'; + +import { asap } from './asap'; + +export default function then(onFulfillment, onRejection) { + const parent = this; + + const child = new this.constructor(noop); + + if (child[PROMISE_ID] === undefined) { + makePromise(child); + } + + const { _state } = parent; + + if (_state) { + const callback = arguments[_state - 1]; + asap(() => invokeCallback(_state, child, callback, parent._result)); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; +} diff --git a/build-templates/wechatgame/lib/es6-promise/utils.js b/build-templates/wechatgame/lib/es6-promise/utils.js new file mode 100644 index 0000000..72545c5 --- /dev/null +++ b/build-templates/wechatgame/lib/es6-promise/utils.js @@ -0,0 +1,21 @@ +export function objectOrFunction(x) { + let type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} + +export function isFunction(x) { + return typeof x === 'function'; +} + +export function isMaybeThenable(x) { + return x !== null && typeof x === 'object'; +} + +let _isArray; +if (Array.isArray) { + _isArray = Array.isArray; +} else { + _isArray = x => Object.prototype.toString.call(x) === '[object Array]'; +} + +export const isArray = _isArray; diff --git a/build-templates/wechatgame/lib/fix-symbol.js b/build-templates/wechatgame/lib/fix-symbol.js new file mode 100644 index 0000000..b5d5577 --- /dev/null +++ b/build-templates/wechatgame/lib/fix-symbol.js @@ -0,0 +1,66 @@ +(function () { + try { + console.log("[Fix] Starting Symbol.metadata replacement (WeChat Safe Mode)..."); + + // 1. 安全获取全局对象 (兼容微信小游戏/Web/Node) + var root = (typeof globalThis !== 'undefined') ? globalThis : + (typeof GameGlobal !== 'undefined') ? GameGlobal : + (typeof window !== 'undefined') ? window : + (typeof self !== 'undefined') ? self : this; + + // 2. 获取原生 Symbol + var NativeSymbol = root.Symbol; + if (!NativeSymbol) { + console.warn("[Fix] Symbol not found, skipping."); + return; + } + + // 3. 生成一个全新的 Symbol 作为 metadata 的替代品 + // 这个 Symbol 不在 Function.prototype 上,所以不会触发只读错误 + var CustomMetadataSymbol = NativeSymbol("Symbol.metadata.custom"); + + // 4. 创建 Symbol 的代理构造函数 + var SymbolProxy = function (description) { + return NativeSymbol(description); + }; + + // 5. 复制原生 Symbol 的所有静态属性 (iterator, species, for, keyFor 等) + // 使用 Reflect.ownKeys 以确保复制完整 + if (typeof Reflect !== 'undefined' && Reflect.ownKeys) { + Reflect.ownKeys(NativeSymbol).forEach(function (key) { + // 跳过这些属性,避免报错 + if (key === 'metadata' || key === 'length' || key === 'name' || key === 'arguments' || key === 'caller' || key === 'prototype') return; + + try { + var desc = Object.getOwnPropertyDescriptor(NativeSymbol, key); + if (desc) Object.defineProperty(SymbolProxy, key, desc); + } catch (e) {} + }); + } else { + // 降级方案 (如果在极老的环境) + for (var key in NativeSymbol) { + if (key !== 'metadata') SymbolProxy[key] = NativeSymbol[key]; + } + } + + // 6. 恢复原型链指向 + SymbolProxy.prototype = NativeSymbol.prototype; + + // 7. 【关键】将 metadata 指向我们自定义的 Symbol + // 这样外界调用 Symbol.metadata 时,拿到的实际上是 CustomMetadataSymbol + Object.defineProperty(SymbolProxy, "metadata", { + value: CustomMetadataSymbol, + configurable: false, + writable: false, + enumerable: false + }); + + // 8. 覆盖全局 Symbol + root.Symbol = SymbolProxy; + + console.log("[Fix] Symbol.metadata successfully patched globally."); + + } catch (e) { + console.error("[Fix] Patch failed:", e); + } +})(); \ No newline at end of file diff --git a/doc/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js b/doc/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js index 9df9282..7923248 100644 --- a/doc/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js +++ b/doc/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js @@ -6,6 +6,7 @@ (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) { @@ -5767,14 +5768,19 @@ * @param headers custom headers to send with the connection (only supported in Node.js. Web Browsers do not allow setting custom headers) */ connect(url, headers) { - // try { - // // Node or Bun environments (supports custom headers) - // this.ws = new WebSocket(url, { headers, protocols: this.protocols }); - // } - // catch (e) { + try { + // Adding the following line will work fine + if (globalThis?.wx) throw new Error("WeChat Mini Program does not support custom headers"); + + // On WeChat environments, will always block here, will not continue to run, and will not report an error + // Node or Bun environments (supports custom headers) + this.ws = new WebSocket(url, { headers, protocols: this.protocols }); // + + } + catch (e) { // browser environment (custom headers not supported) this.ws = new WebSocket(url, this.protocols); - // } + } this.ws.binaryType = 'arraybuffer'; this.ws.onopen = this.events.onopen; this.ws.onmessage = this.events.onmessage; diff --git a/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js b/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js index 9df9282..7923248 100644 --- a/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js +++ b/extensions/Colyseus Multiplayer SDK/runtime/colyseus.js @@ -6,6 +6,7 @@ (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) { @@ -5767,14 +5768,19 @@ * @param headers custom headers to send with the connection (only supported in Node.js. Web Browsers do not allow setting custom headers) */ connect(url, headers) { - // try { - // // Node or Bun environments (supports custom headers) - // this.ws = new WebSocket(url, { headers, protocols: this.protocols }); - // } - // catch (e) { + try { + // Adding the following line will work fine + if (globalThis?.wx) throw new Error("WeChat Mini Program does not support custom headers"); + + // On WeChat environments, will always block here, will not continue to run, and will not report an error + // Node or Bun environments (supports custom headers) + this.ws = new WebSocket(url, { headers, protocols: this.protocols }); // + + } + catch (e) { // browser environment (custom headers not supported) this.ws = new WebSocket(url, this.protocols); - // } + } this.ws.binaryType = 'arraybuffer'; this.ws.onopen = this.events.onopen; this.ws.onmessage = this.events.onmessage; diff --git a/package-lock.json b/package-lock.json index edd3d63..ad6d0a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "name": "CGamesClient", "dependencies": { "@msgpack/msgpack": "^3.1.1", - "core-js": "^3.42.0" + "core-js": "^3.47.0" } }, "node_modules/@msgpack/msgpack": { @@ -20,10 +20,11 @@ } }, "node_modules/core-js": { - "version": "3.42.0", - "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.42.0.tgz", - "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "hasInstallScript": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" diff --git a/package.json b/package.json index 3f1f89c..227e797 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,6 @@ }, "dependencies": { "@msgpack/msgpack": "^3.1.1", - "core-js": "^3.42.0" + "core-js": "^3.47.0" } } diff --git a/tsconfig.json b/tsconfig.json index 052f627..840af82 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,22 +3,13 @@ "extends": "./temp/tsconfig.cocos.json", /* Add your custom configuration here. */ "compilerOptions": { - "lib": [ - "DOM", - "ES2017" - ], "strict": false, "allowSyntheticDefaultImports": true, - "allowJs": true - }, - "exclude": [ - "build", - "build-templates", - "doc", - "library", - "node_modules", - "profiles", - "settings", - "temp" - ] -} \ No newline at end of file + "esModuleInterop": true, + + "target": "ES2018", + "experimentalDecorators": true, // 关键:开启旧版装饰器 + "emitDecoratorMetadata": true, // 关键:配合 Colyseus 使用 + "useDefineForClassFields": false // 建议:防止某些属性初始化的差异 + } +}