From 1d0ad3fd9976e735668435834864936137904e9b Mon Sep 17 00:00:00 2001 From: JianMiau Date: Mon, 26 Aug 2024 16:44:51 +0800 Subject: [PATCH] [add] slot1 --- package-lock.json | 855 +++++++++++++++++- package.json | 10 +- src/CatanEngine/CSharp/String.ts | 16 + src/CatanEngine/CSharp/System/Action.ts | 125 +++ .../CSharp/System/ActionWithType.ts | 166 ++++ .../CSharp/System/ActionWithType2.ts | 166 ++++ .../CSharp/System/Text/Encoding.ts | 106 +++ .../CoroutineV2/CancellationTokenSource.ts | 43 + .../CoroutineV2/Core/ActionEnumerator.ts | 17 + .../CoroutineV2/Core/BaseEnumerator.ts | 131 +++ .../CoroutineV2/Core/CoroutineExecutor.ts | 103 +++ .../CoroutineV2/Core/EnumeratorExecutor.ts | 169 ++++ .../CoroutineV2/Core/ParallelEnumerator.ts | 46 + .../CoroutineV2/Core/SingleEnumerator.ts | 18 + .../CoroutineV2/Core/WaitTimeEnumerator.ts | 21 + src/CatanEngine/CoroutineV2/CoroutineV2.ts | 75 ++ src/CatanEngine/CoroutineV2/IEnumeratorV2.ts | 16 + src/NetConnector1.ts | 6 + src/Utils/CCExtensions/ArrayExtension.ts | 140 +++ src/Utils/CCExtensions/NumberExtension.ts | 187 ++++ src/Utils/Number/NumberEx.ts | 180 ++++ src/Utils/Number/RandomEx.ts | 92 ++ src/Utils/Singleton/BaseSingleton.ts | 27 + src/Utils/Singleton/BaseSingletonV2.ts | 28 + src/Utils/catan.ts | 16 + src/api/account/login.ts | 18 + src/api/slot/ae.ts | 8 + src/api/slot/in.ts | 16 + src/api/slot1/fgspin.ts | 28 + src/api/slot1/spin.ts | 32 + src/electron/main.ts | 99 +- src/electron/preload.ts | 5 +- src/electron/renderer.ts | 17 +- src/global.d.ts | 2 +- src/pkg/server.ts | 13 + .../NetManagerV2/Core/INetConnector.ts | 13 + .../NetManagerV2/Core/INetConnector.ts.meta | 10 + .../NetManagerV2/Core/INetRequest.ts | 17 + .../NetManagerV2/Core/INetRequest.ts.meta | 10 + .../NetManagerV2/Core/INetResponse.ts | 6 + .../NetManagerV2/Core/INetResponse.ts.meta | 10 + .../CatanEngine/NetManagerV2/NetConfig.ts | 4 + .../CatanEngine/NetManagerV2/NetConnector.ts | 149 +++ .../CatanEngine/NetManagerV2/NetManager.ts | 53 ++ .../CatanEngine/NetManagerV2/NetRequest.ts | 21 + src/shared/.gitkeep | 0 src/shared/protocols/AccountRequest.ts | 6 + src/shared/protocols/Slot1Request.ts | 6 + src/shared/protocols/SlotRequest.ts | 6 + src/shared/protocols/define/enum.ts | 4 + src/shared/protocols/define/interface.ts | 9 + tsconfig.json | 17 +- tsrpc.config.ts | 38 + 53 files changed, 3299 insertions(+), 77 deletions(-) create mode 100644 src/CatanEngine/CSharp/String.ts create mode 100644 src/CatanEngine/CSharp/System/Action.ts create mode 100644 src/CatanEngine/CSharp/System/ActionWithType.ts create mode 100644 src/CatanEngine/CSharp/System/ActionWithType2.ts create mode 100644 src/CatanEngine/CSharp/System/Text/Encoding.ts create mode 100644 src/CatanEngine/CoroutineV2/CancellationTokenSource.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/ActionEnumerator.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/BaseEnumerator.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/CoroutineExecutor.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/EnumeratorExecutor.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/ParallelEnumerator.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/SingleEnumerator.ts create mode 100644 src/CatanEngine/CoroutineV2/Core/WaitTimeEnumerator.ts create mode 100644 src/CatanEngine/CoroutineV2/CoroutineV2.ts create mode 100644 src/CatanEngine/CoroutineV2/IEnumeratorV2.ts create mode 100644 src/NetConnector1.ts create mode 100644 src/Utils/CCExtensions/ArrayExtension.ts create mode 100644 src/Utils/CCExtensions/NumberExtension.ts create mode 100644 src/Utils/Number/NumberEx.ts create mode 100644 src/Utils/Number/RandomEx.ts create mode 100644 src/Utils/Singleton/BaseSingleton.ts create mode 100644 src/Utils/Singleton/BaseSingletonV2.ts create mode 100644 src/Utils/catan.ts create mode 100644 src/api/account/login.ts create mode 100644 src/api/slot/ae.ts create mode 100644 src/api/slot/in.ts create mode 100644 src/api/slot1/fgspin.ts create mode 100644 src/api/slot1/spin.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts.meta create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts.meta create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts.meta create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/NetConfig.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/NetConnector.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/NetManager.ts create mode 100644 src/script/Engine/CatanEngine/NetManagerV2/NetRequest.ts create mode 100644 src/shared/.gitkeep create mode 100644 src/shared/protocols/AccountRequest.ts create mode 100644 src/shared/protocols/Slot1Request.ts create mode 100644 src/shared/protocols/SlotRequest.ts create mode 100644 src/shared/protocols/define/enum.ts create mode 100644 src/shared/protocols/define/interface.ts create mode 100644 tsrpc.config.ts diff --git a/package-lock.json b/package-lock.json index 0cabdbe..5c8b504 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,13 +11,14 @@ "dependencies": { "dayjs": "^1.11.13", "dotenv": "^16.4.5", + "module-alias": "^2.2.3", + "tsrpc": "^3.4.16", "ws": "^8.18.0" }, "bin": { "sdserver": "dist/server.js" }, "devDependencies": { - "@types/electron": "^1.6.10", "@types/node": "^22.5.0", "@types/ws": "^8.5.12", "copyfiles": "^2.4.1", @@ -26,6 +27,7 @@ "electron-packager": "^17.1.2", "nodemon": "^3.1.4", "ts-node": "^10.9.2", + "tsrpc-cli": "^2.4.5", "typescript": "^5.5.4" } }, @@ -546,16 +548,6 @@ "@types/ms": "*" } }, - "node_modules/@types/electron": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@types/electron/-/electron-1.6.10.tgz", - "integrity": "sha512-MOCVyzIwkBEloreoCVrTV108vSf8fFIJPsGruLCoAoBZdxtnJUqKA4lNonf/2u1twSjAspPEfmEheC+TLm/cMw==", - "deprecated": "This is a stub types definition for electron (https://github.com/electron/electron). electron provides its own type definitions, so you don't need @types/electron installed!", - "dev": true, - "dependencies": { - "electron": "*" - } - }, "node_modules/@types/fs-extra": { "version": "9.0.13", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", @@ -590,7 +582,6 @@ "version": "22.5.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", - "dev": true, "dependencies": { "undici-types": "~6.19.2" } @@ -717,6 +708,33 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -730,7 +748,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1178,7 +1195,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -1190,7 +1206,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1218,15 +1233,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/bl/node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -1429,7 +1442,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1445,7 +1457,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1454,7 +1465,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -1462,6 +1472,12 @@ "node": ">=8" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1516,6 +1532,30 @@ "node": ">=8" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", @@ -1533,6 +1573,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -1544,6 +1593,15 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-response": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", @@ -1560,7 +1618,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1571,8 +1628,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -1595,6 +1651,12 @@ "node": ">= 6" } }, + "node_modules/commandpost": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", + "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", + "dev": true + }, "node_modules/compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", @@ -1936,6 +1998,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -2117,6 +2191,52 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/editorconfig/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/editorconfig/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", @@ -2516,6 +2636,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/external-editor/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor/node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/extract-zip": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", @@ -2567,6 +2754,30 @@ "pend": "~1.2.0" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -3146,6 +3357,15 @@ "node": ">= 6" } }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, "node_modules/iconv-corefoundation": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", @@ -3218,6 +3438,58 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/invert-kv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz", + "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sindresorhus/invert-kv?sponsor=1" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3308,6 +3580,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3317,6 +3598,30 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -3447,6 +3752,37 @@ "node": ">=8" } }, + "node_modules/k8w-crypto": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/k8w-crypto/-/k8w-crypto-0.2.0.tgz", + "integrity": "sha512-M6u4eQ6CQaU5xO3s4zaUUp9G79xNDhXtTU0X7N80tDcBhQC5ggowlyOzj95v7WiCuk7xkV0aFsTmCpuf0m0djw==", + "dev": true + }, + "node_modules/k8w-extend-native": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/k8w-extend-native/-/k8w-extend-native-1.4.6.tgz", + "integrity": "sha512-AHTCyFshldMme0s9FKD+QKG+QZdBkHXzl+8kYfNhsSDhcdQ5TYWQwphjecSJjxNdGd78TIbO0fHiOvM+Ei22YA==", + "dependencies": { + "k8w-linq-array": "*", + "k8w-super-date": "*", + "k8w-super-object": "*" + } + }, + "node_modules/k8w-linq-array": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/k8w-linq-array/-/k8w-linq-array-0.2.8.tgz", + "integrity": "sha512-4IAkQN8UJdk804tQi++wuwSZvFWk/Wcl1uG5PR/0c0YvB5hUd2f8tJm3OgOMOxjV9UVByNLvnPYGIwrFQPpjlA==" + }, + "node_modules/k8w-super-date": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/k8w-super-date/-/k8w-super-date-0.1.3.tgz", + "integrity": "sha512-IBqKOAMAXR/bgzu+rYI30tEMP/Y6Q8HQuqJiTkE2mLJg11yok9guoi8uZTynTahviVBndcfBpOgi1H/zhihv7w==" + }, + "node_modules/k8w-super-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/k8w-super-object/-/k8w-super-object-0.3.0.tgz", + "integrity": "sha512-u2jfh4goYXKZmSucaLaOTaNbLRatjv0CSRpzE0KU0732+9XtYZFd5vrdw/mzJfK5fPHb/zyikOSHDX5mJrav+g==" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3508,6 +3844,18 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/lcid": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz", + "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==", + "dev": true, + "dependencies": { + "invert-kv": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -3583,6 +3931,22 @@ "dev": true, "peer": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -3610,6 +3974,18 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -3623,6 +3999,26 @@ "node": ">=10" } }, + "node_modules/mem": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", + "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^2.1.0", + "p-is-promise": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -3656,6 +4052,15 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -3732,12 +4137,23 @@ "node": ">=10" } }, + "node_modules/module-alias": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.3.tgz", + "integrity": "sha512-23g5BFj4zdQL/b6tor7Ji+QY4pEfNH784BMslY9Qb0UnJWRAt+lQGLYmRaM0KDBwIG23ffEBELhZDP2rhi9f/Q==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "node_modules/node-addon-api": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", @@ -3825,6 +4241,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -3844,6 +4272,70 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-locale": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-5.0.0.tgz", + "integrity": "sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==", + "dev": true, + "dependencies": { + "execa": "^4.0.0", + "lcid": "^3.0.0", + "mem": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -3853,6 +4345,24 @@ "node": ">=8" } }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -4052,6 +4562,12 @@ "node": ">=10" } }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -4255,6 +4771,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -4282,6 +4817,24 @@ "node": ">=8.0" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4365,6 +4918,12 @@ "node": ">=8" } }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", + "dev": true + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -4551,6 +5110,15 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", @@ -4733,6 +5301,12 @@ "node": ">= 10.0.0" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -4885,6 +5459,200 @@ } } }, + "node_modules/tsbuffer": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/tsbuffer/-/tsbuffer-2.2.9.tgz", + "integrity": "sha512-PZtbjmtMDziIi1/RPn1LMuMTmNUsZajB+Ziz+HxonAxswXeam0ukTwjQ2eYR6J1JOffz7E8z5ip+NrYZ7wGnBQ==", + "dependencies": { + "k8w-extend-native": "^1.4.6", + "tsbuffer-validator": "^2.1.2", + "tslib": "*" + } + }, + "node_modules/tsbuffer-proto-generator": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/tsbuffer-proto-generator/-/tsbuffer-proto-generator-1.7.2.tgz", + "integrity": "sha512-Rjq/mNXb6Z3ORi5M0BH3O+L0hpr+RcLzJ1edXO4bOZkojdtxDmwoKGBKoh+/xba+bhOiSiwHfVZLiQ06A6vEmw==", + "dev": true, + "dependencies": { + "k8w-crypto": "^0.2.0", + "k8w-extend-native": "^1.4.6", + "tsbuffer-schema": "^2.2.0", + "tslib": "*", + "typescript": "^4" + } + }, + "node_modules/tsbuffer-proto-generator/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/tsbuffer-schema": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tsbuffer-schema/-/tsbuffer-schema-2.2.0.tgz", + "integrity": "sha512-I4+5Xfk7G+D++kXdNnYTeY26WQTaf14C84XQwPKteNmrwxRY3CQCkMqASRiCUqtpOuDn43qmoxuXpT+Vo8Wltg==" + }, + "node_modules/tsbuffer-validator": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tsbuffer-validator/-/tsbuffer-validator-2.1.2.tgz", + "integrity": "sha512-PrqIYy7aANY7ssr92HJN8ZM+eGc4Qmpvu7nNBv+T2DOAb+eqblKjlDZEhNnzxjs/ddqu9PqPe4Aa+fqYdzo98g==", + "dependencies": { + "k8w-extend-native": "^1.4.6", + "tsbuffer-schema": "^2.2.0", + "tslib": "*" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" + }, + "node_modules/tsrpc": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/tsrpc/-/tsrpc-3.4.16.tgz", + "integrity": "sha512-rUiaQNJJwZlOwTwnbZfNb2JJYL0Y/lZ/GVAtRYwFMzq7Z2H7dI4kB3oPakpu4+g3+i8radFPXfTsPkcNF1iAUg==", + "dependencies": { + "@types/ws": "^7.4.7", + "chalk": "^4.1.2", + "tsbuffer": "^2.2.9", + "tsrpc-base-client": "^2.1.15", + "tsrpc-proto": "^1.4.3", + "uuid": "^8.3.2", + "ws": "^7.5.9" + } + }, + "node_modules/tsrpc-base-client": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/tsrpc-base-client/-/tsrpc-base-client-2.1.15.tgz", + "integrity": "sha512-ejIsGKF1MtcS2Mqpv1JYjoOmFbkOMaubb0FYglA52Sfl0glnq2UAqbCu5embQISzuIF9DiDeg1Rui9EyOc2hdA==", + "dependencies": { + "k8w-extend-native": "^1.4.6", + "tsbuffer": "^2.2.9", + "tslib": "*", + "tsrpc-proto": "^1.4.3" + } + }, + "node_modules/tsrpc-cli": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/tsrpc-cli/-/tsrpc-cli-2.4.5.tgz", + "integrity": "sha512-/3MMyGAAuSnZLQVfoRZXI5sfyGakRTk2AfrllvVSUSfGPTr06iU1YAgOATNYEHl+uAj1+QFz3dKT8g3J+wCIcw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "fs-extra": "^10.1.0", + "glob": "^7.2.3", + "inquirer": "^8.2.4", + "k8w-extend-native": "^1.4.6", + "minimist": "^1.2.6", + "ora": "^5.4.1", + "os-locale": "^5.0.0", + "ts-node": "^10.8.2", + "tsbuffer": "^2.2.3", + "tsbuffer-proto-generator": "^1.7.2", + "tsbuffer-schema": "^2.2.0", + "tsrpc-proto": "^1.4.2", + "typescript": "^4.7.4", + "typescript-formatter": "^7.2.2" + }, + "bin": { + "tsrpc": "bin.js", + "tsrpc-cli": "bin.js" + } + }, + "node_modules/tsrpc-cli/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tsrpc-cli/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/tsrpc-cli/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/tsrpc-cli/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/tsrpc-proto": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/tsrpc-proto/-/tsrpc-proto-1.4.3.tgz", + "integrity": "sha512-qtkk5i34m9/K1258EdyXAEikU/ADPELHCCXN/oFJ4XwH+kN3kXnKYmwCDblUuMA73V2+A/EwkgUGyAgPa335Hw==", + "dependencies": { + "tsbuffer-schema": "^2.2.0", + "tslib": "*" + } + }, + "node_modules/tsrpc/node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/tsrpc/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", @@ -4911,6 +5679,25 @@ "node": ">=14.17" } }, + "node_modules/typescript-formatter": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", + "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", + "dev": true, + "dependencies": { + "commandpost": "^1.0.0", + "editorconfig": "^0.15.0" + }, + "bin": { + "tsfmt": "bin/tsfmt" + }, + "engines": { + "node": ">= 4.2.0" + }, + "peerDependencies": { + "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -4920,8 +5707,7 @@ "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, "node_modules/universalify": { "version": "0.1.2", @@ -4962,6 +5748,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -5000,6 +5794,15 @@ "dev": true, "optional": true }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 74b753c..a45adbd 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "tsc && copyfiles -u 1 src/electron/index.html dist/ && copyfiles -u 1 src/electron/index.css dist/", "pack": "electron-packager . SDServer --platform=win32 --arch=x64 --out=dist/", "buildexe": "npx electron-builder", + "api": "tsrpc-cli proto && tsrpc-cli api", "watch": "nodemon" }, "build": { @@ -23,10 +24,11 @@ "dependencies": { "dayjs": "^1.11.13", "dotenv": "^16.4.5", + "module-alias": "^2.2.3", + "tsrpc": "^3.4.16", "ws": "^8.18.0" }, "devDependencies": { - "@types/electron": "^1.6.10", "@types/node": "^22.5.0", "@types/ws": "^8.5.12", "copyfiles": "^2.4.1", @@ -35,8 +37,12 @@ "electron-packager": "^17.1.2", "nodemon": "^3.1.4", "ts-node": "^10.9.2", + "tsrpc-cli": "^2.4.5", "typescript": "^5.5.4" }, + "_moduleAliases": { + "@": "dist" + }, "bin": "dist/server.js", "pkg": { "assets": [ @@ -50,4 +56,4 @@ "author": "", "license": "ISC", "description": "" -} +} \ No newline at end of file diff --git a/src/CatanEngine/CSharp/String.ts b/src/CatanEngine/CSharp/String.ts new file mode 100644 index 0000000..ad83796 --- /dev/null +++ b/src/CatanEngine/CSharp/String.ts @@ -0,0 +1,16 @@ +interface StringConstructor { + IsNullOrEmpty: (value: string) => boolean; + Format: (format: string, ...args: any[]) => string; +} + +String.IsNullOrEmpty = function (value: string): boolean { + return value === undefined || value === null || value.trim() === ''; +}; + +String.Format = function (format: string, ...args: any[]): string { + return format.replace(/{(\d+)}/g, (match, index) => { + let value = args[index]; + if (value === null || value === undefined) return ''; + return '' + value; + }); +} diff --git a/src/CatanEngine/CSharp/System/Action.ts b/src/CatanEngine/CSharp/System/Action.ts new file mode 100644 index 0000000..e681833 --- /dev/null +++ b/src/CatanEngine/CSharp/System/Action.ts @@ -0,0 +1,125 @@ +/** + * 回呼函數: fnname (arg: TArg): void + */ +interface ActionCallback { + (arg: TArg): void; +} + +interface Struct { + callback: ActionCallback; + target: any; + once?: boolean; +} + +export class Action { + private _queue: Struct[] = []; + + /** + * 監聽事件 + * @param callback 回呼函數: fnname (arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallback(callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget + }; + this._queue.push(q); + } + + /** + * 監聽事件 (一次性) + * @param callback 回呼函數: fnname (arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallbackOnce(callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget, + once: true + }; + this._queue.push(q); + } + + /** + * 移除事件 + * @param callback + */ + RemoveByCallback(callback: ActionCallback) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.callback === callback) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param bindTarget 回呼時this綁定的對象 + */ + RemoveByBindTarget(bindTarget: any) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.target === bindTarget) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除全部事件 + */ + RemoveAllCallbacks() { + this._queue.forEach(q => q.callback = undefined); + this._queue.length = 0; + } + + /** + * 發送事件 + * @param arg 參數 + */ + DispatchCallback(arg: TArg) { + let index = this._queue.length; + if (index > 0) { + let cleanRemoved = false; + this._queue.slice().forEach(q => { + if (!q.callback) { + cleanRemoved = true; + return; + } + + if (q.target) { + q.callback.call(q.target, arg); + } else { + q.callback(arg); + } + + if (q.once) { + q.callback = undefined; + cleanRemoved = true; + } + }); + + if (cleanRemoved) { + index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback) { + this._queue.splice(index, 1); + } + } + } + } + } + } +} diff --git a/src/CatanEngine/CSharp/System/ActionWithType.ts b/src/CatanEngine/CSharp/System/ActionWithType.ts new file mode 100644 index 0000000..1a078ee --- /dev/null +++ b/src/CatanEngine/CSharp/System/ActionWithType.ts @@ -0,0 +1,166 @@ +/** + * 回呼函數: fnname (arg: TArg): void + */ +interface ActionCallback { + (arg: TArg): void; +} + +interface Struct { + callback: ActionCallback; + target: any; + type: TType; + once?: boolean; +} + +export class ActionWithType { + private _queue: Struct[] = []; + + /** + * 監聽事件 + * @param callback 回呼函數: fnname (arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallback(type: TType, callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget, + type: type + }; + this._queue.push(q); + } + + /** + * 監聽事件 (一次性) + * @param callback 回呼函數: fnname (arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallbackOnce(type: TType, callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget, + type: type, + once: true + }; + this._queue.push(q); + } + + /** + * 移除事件 + * @param callback + */ + RemoveByCallback(callback: ActionCallback) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.callback === callback) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param bindTarget 回呼時this綁定的對象 + */ + RemoveByBindTarget(bindTarget: any) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.target === bindTarget) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param type 事件類型 + */ + RemoveByType(type: TType) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.type === type) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param type 事件類型 + * @param callback + */ + RemoveCallback(type:TType, callback: ActionCallback) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || (q.type === type && q.callback === callback)) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除全部事件 + */ + RemoveAllCallbacks() { + this._queue.forEach(q => q.callback = undefined); + this._queue.length = 0; + } + + /** + * 發送事件 + * @param type 事件類型 + * @param arg 參數 + */ + DispatchCallback(type: TType, arg: TArg) { + let index = this._queue.length; + if (index > 0) { + let cleanRemoved = false; + this._queue.slice().forEach(q => { + if (!q.callback) + { + cleanRemoved = true; + return; + } + if (q.type !== type) return; + + if (q.target) { + q.callback.call(q.target, arg); + } else { + q.callback(arg); + } + + if (q.once) { + q.callback = undefined; + cleanRemoved = true; + } + }); + + if (cleanRemoved) { + index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback) { + this._queue.splice(index, 1); + } + } + } + } + } + } +} diff --git a/src/CatanEngine/CSharp/System/ActionWithType2.ts b/src/CatanEngine/CSharp/System/ActionWithType2.ts new file mode 100644 index 0000000..33e8c75 --- /dev/null +++ b/src/CatanEngine/CSharp/System/ActionWithType2.ts @@ -0,0 +1,166 @@ +/** + * 回呼函數: fnname (type: TType, arg: TArg): void + */ +interface ActionCallback { + (type: TType, arg: TArg): void; +} + +interface Struct { + callback: ActionCallback; + target: any; + type: TType; + once?: boolean; +} + +export class ActionWithType2 { + private _queue: Struct[] = []; + + /** + * 監聽事件 + * @param callback 回呼函數: fnname (type: TType, arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallback(type: TType, callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget, + type: type + }; + this._queue.push(q); + } + + /** + * 監聽事件 (一次性) + * @param callback 回呼函數: fnname (type: TType, arg: TArg): void + * @param bindTarget 回呼時this綁定的對象 + */ + AddCallbackOnce(type: TType, callback: ActionCallback, bindTarget?: any) { + let q = > { + callback: callback, + target: bindTarget, + type: type, + once: true + }; + this._queue.push(q); + } + + /** + * 移除事件 + * @param callback + */ + RemoveByCallback(callback: ActionCallback) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.callback === callback) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param bindTarget 回呼時this綁定的對象 + */ + RemoveByBindTarget(bindTarget: any) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.target === bindTarget) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param type 事件類型 + */ + RemoveByType(type: TType) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || q.type === type) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除事件 + * @param type 事件類型 + * @param callback + */ + RemoveCallback(type:TType, callback: ActionCallback) { + let index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback || (q.type === type && q.callback === callback)) { + q.callback = undefined; + this._queue.splice(index, 1); + } + } + } + } + + /** + * 移除全部事件 + */ + RemoveAllCallbacks() { + this._queue.forEach(q => q.callback = undefined); + this._queue.length = 0; + } + + /** + * 發送事件 + * @param type 事件類型 + * @param arg 參數 + */ + DispatchCallback(type: TType, arg: TArg) { + let index = this._queue.length; + if (index > 0) { + let cleanRemoved = false; + this._queue.slice().forEach(q => { + if (!q.callback) + { + cleanRemoved = true; + return; + } + if (q.type !== type) return; + + if (q.target) { + q.callback.call(q.target, type, arg); + } else { + q.callback(type, arg); + } + + if (q.once) { + q.callback = undefined; + cleanRemoved = true; + } + }); + + if (cleanRemoved) { + index = this._queue.length; + if (index > 0) { + while (index--) { + let q = this._queue[index]; + if (!q.callback) { + this._queue.splice(index, 1); + } + } + } + } + } + } +} diff --git a/src/CatanEngine/CSharp/System/Text/Encoding.ts b/src/CatanEngine/CSharp/System/Text/Encoding.ts new file mode 100644 index 0000000..25f60ed --- /dev/null +++ b/src/CatanEngine/CSharp/System/Text/Encoding.ts @@ -0,0 +1,106 @@ +export module Encoding.UTF8 { + + export function GetBytes(str: string) { + let len = str.length, resPos = -1; + let resArr = new Uint8Array(len * 3); + for (let point = 0, nextcode = 0, i = 0; i !== len;) { + point = str.charCodeAt(i), i += 1; + if (point >= 0xD800 && point <= 0xDBFF) { + if (i === len) { + resArr[resPos += 1] = 0xef; + resArr[resPos += 1] = 0xbf; + resArr[resPos += 1] = 0xbd; + break; + } + + nextcode = str.charCodeAt(i); + if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) { + point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000; + i += 1; + if (point > 0xffff) { + resArr[resPos += 1] = (0x1e << 3) | (point >>> 18); + resArr[resPos += 1] = (0x2 << 6) | ((point >>> 12) & 0x3f); + resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); + resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); + continue; + } + } else { + resArr[resPos += 1] = 0xef; + resArr[resPos += 1] = 0xbf; + resArr[resPos += 1] = 0xbd; + continue; + } + } + if (point <= 0x007f) { + resArr[resPos += 1] = (0x0 << 7) | point; + } else if (point <= 0x07ff) { + resArr[resPos += 1] = (0x6 << 5) | (point >>> 6); + resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); + } else { + resArr[resPos += 1] = (0xe << 4) | (point >>> 12); + resArr[resPos += 1] = (0x2 << 6) | ((point >>> 6) & 0x3f); + resArr[resPos += 1] = (0x2 << 6) | (point & 0x3f); + } + } + return resArr.subarray(0, resPos + 1); + } + + export function GetString(array: Uint8Array) { + var charCache = new Array(128); + var codePt, byte1; + var result = []; + var buffLen = array.length; + var charFromCodePt = String.fromCodePoint || String.fromCharCode; + for (var i = 0; i < buffLen;) { + byte1 = array[i++]; + + if (byte1 <= 0x7F) { + codePt = byte1; + } else if (byte1 <= 0xDF) { + codePt = ((byte1 & 0x1F) << 6) | (array[i++] & 0x3F); + } else if (byte1 <= 0xEF) { + codePt = ((byte1 & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F); + } else if (String.fromCodePoint) { + codePt = ((byte1 & 0x07) << 18) | ((array[i++] & 0x3F) << 12) | ((array[i++] & 0x3F) << 6) | (array[i++] & 0x3F); + } else { + codePt = 63; // Cannot convert four byte code points, so use "?" instead + i += 3; + } + result.push(charCache[codePt] || (charCache[codePt] = charFromCodePt(codePt))); + } + return result.join(''); + } + + /** + * 是否非中英文 + * @param {string} msg 訊息 + */ + export function IsNotChineseOrEnglish(str: string): boolean { + var regExp: RegExp = /^[\u3105-\u312c\u4e00-\u9fff\uff10-\uff19\uFF21-\uFF3AA-Za-z0-9_]+$/; + if (str.match(regExp)) { + return true; + } else { + return false; + } + } + + export function b64EncodeUnicode(str) { + return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { + //@ts-ignore + return String.fromCharCode('0x' + p1); + })); + } + export function b64DecodeUnicode(str) { + return decodeURIComponent(atob(str).split('').map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + } + export function isBase64(str) { + if (str === '' || str.trim() === '') { return false; } + try { + return btoa(atob(str)) == str; + } catch (err) { + return false; + } + } +} \ No newline at end of file diff --git a/src/CatanEngine/CoroutineV2/CancellationTokenSource.ts b/src/CatanEngine/CoroutineV2/CancellationTokenSource.ts new file mode 100644 index 0000000..6b264b9 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/CancellationTokenSource.ts @@ -0,0 +1,43 @@ +const CANCEL = Symbol(); + +export interface CancellationToken { + readonly IsCancellationRequested: boolean; + ThrowIfCancellationRequested(): void; +} + +export class CancellationTokenSource { + readonly Token: CancellationToken; + + constructor() { + this.Token = new CancellationTokenImpl(); + } + + Cancel() { + this.Token[CANCEL](); + } +} + +export class TaskCancelledException extends Error { + constructor() { + super("Task Cancelled"); + Reflect.setPrototypeOf(this, TaskCancelledException.prototype); + } +} + +class CancellationTokenImpl implements CancellationToken { + IsCancellationRequested: boolean; + + constructor() { + this.IsCancellationRequested = false; + } + + ThrowIfCancellationRequested() { + if (this.IsCancellationRequested) { + throw new TaskCancelledException(); + } + } + + [CANCEL]() { + this.IsCancellationRequested = true; + } +} diff --git a/src/CatanEngine/CoroutineV2/Core/ActionEnumerator.ts b/src/CatanEngine/CoroutineV2/Core/ActionEnumerator.ts new file mode 100644 index 0000000..ddd1dae --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/ActionEnumerator.ts @@ -0,0 +1,17 @@ +import { BaseEnumerator } from "./BaseEnumerator"; + +export class ActionEnumerator extends BaseEnumerator { + private _action: Function; + + constructor(action: Function) { + super(); + this._action = action; + } + + next(value?: any): IteratorResult { + if (this._action) { + this._action(); + } + return { done: true, value: undefined }; + } +} diff --git a/src/CatanEngine/CoroutineV2/Core/BaseEnumerator.ts b/src/CatanEngine/CoroutineV2/Core/BaseEnumerator.ts new file mode 100644 index 0000000..17b9548 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/BaseEnumerator.ts @@ -0,0 +1,131 @@ +import { IEnumeratorV2, IEnumeratorV2Started } from "../IEnumeratorV2"; +import { CoroutineExecutor } from "./CoroutineExecutor"; + +let EnumeratorExecutorClass: typeof import("./EnumeratorExecutor").EnumeratorExecutor = null; +let SingleEnumeratorClass: typeof import("./SingleEnumerator").SingleEnumerator = null; +let ParallelEnumeratorClass: typeof import("./ParallelEnumerator").ParallelEnumerator = null; +let WaitTimeEnumeratorClass: typeof import("./WaitTimeEnumerator").WaitTimeEnumerator = null; +let ActionEnumeratorClass: typeof import("./ActionEnumerator").ActionEnumerator = null; + +export abstract class BaseEnumerator implements IEnumeratorV2 { + public nextEnumerator: BaseEnumerator; + + abstract next(value?: any): IteratorResult; + + public static isInit: boolean = false; + + public static async Init(): Promise { + await Promise.all([ + (async () => { + EnumeratorExecutorClass = (await import("./EnumeratorExecutor")).EnumeratorExecutor; + })(), + (async () => { + SingleEnumeratorClass = (await import("./SingleEnumerator")).SingleEnumerator; + })(), + (async () => { + ParallelEnumeratorClass = (await import("./ParallelEnumerator")).ParallelEnumerator; + })(), + (async () => { + WaitTimeEnumeratorClass = (await import("./WaitTimeEnumerator")).WaitTimeEnumerator; + })(), + (async () => { + ActionEnumeratorClass = (await import("./ActionEnumerator")).ActionEnumerator; + })(), + ]); + BaseEnumerator.isInit = true; + } + + Start(target?: any): IEnumeratorV2Started { + let executor = LazyLoad.EnumeratorExecutor(this, target); + CoroutineExecutor.instance.StartCoroutine(executor); + return executor; + } + + Then(iterator: Iterator): IEnumeratorV2 { + if (!iterator) return this; + + if (iterator instanceof BaseEnumerator) { + BaseEnumerator.getLastEnumerator(this).nextEnumerator = iterator; + return this; + } else { + let enumerator = LazyLoad.SingleEnumerator(iterator); + BaseEnumerator.getLastEnumerator(this).nextEnumerator = enumerator; + return this; + } + } + + ThenSerial(...iterators: Iterator[]): IEnumeratorV2 { + let last = BaseEnumerator.getLastEnumerator(this); + for (let iterator of iterators) { + if (iterator instanceof BaseEnumerator) { + last.nextEnumerator = iterator; + } else { + let enumerator = LazyLoad.SingleEnumerator(iterator); + last.nextEnumerator = enumerator; + } + last = last.nextEnumerator; + } + return this; + } + + ThenParallel(...iterators: Iterator[]): IEnumeratorV2 { + return this.Then(LazyLoad.ParallelEnumerator(...iterators)); + } + + ThenAction(action: Function, delaySeconds?: number): IEnumeratorV2 { + if (delaySeconds > 0) { + return this.ThenSerial(LazyLoad.WaitTimeEnumerator(delaySeconds), LazyLoad.ActionEnumerator(action)); + } else { + return this.Then(LazyLoad.ActionEnumerator(action)); + } + } + + ThenWaitTime(seconds: number): IEnumeratorV2 { + return this.Then(LazyLoad.WaitTimeEnumerator(seconds)); + } + + static getLastEnumerator(enumerator: BaseEnumerator): BaseEnumerator { + let next = enumerator; + while (next.nextEnumerator) { + next = next.nextEnumerator; + } + return next; + } +} + +module LazyLoad { + export function EnumeratorExecutor(enumerator: BaseEnumerator, target: any) { + if (BaseEnumerator.isInit) { + return new EnumeratorExecutorClass(enumerator, target); + } + return new (require("./EnumeratorExecutor") as typeof import("./EnumeratorExecutor")).EnumeratorExecutor(enumerator, target); + } + + export function SingleEnumerator(iterator: Iterator) { + if (BaseEnumerator.isInit) { + return new SingleEnumeratorClass(iterator); + } + return new (require("./SingleEnumerator") as typeof import("./SingleEnumerator")).SingleEnumerator(iterator); + } + + export function ParallelEnumerator(...iterators: Iterator[]) { + if (BaseEnumerator.isInit) { + return new ParallelEnumeratorClass(iterators); + } + return new (require("./ParallelEnumerator") as typeof import("./ParallelEnumerator")).ParallelEnumerator(iterators); + } + + export function WaitTimeEnumerator(seconds: number) { + if (BaseEnumerator.isInit) { + return new WaitTimeEnumeratorClass(seconds); + } + return new (require("./WaitTimeEnumerator") as typeof import("./WaitTimeEnumerator")).WaitTimeEnumerator(seconds); + } + + export function ActionEnumerator(action: Function) { + if (BaseEnumerator.isInit) { + return new ActionEnumeratorClass(action); + } + return new (require("./ActionEnumerator") as typeof import("./ActionEnumerator")).ActionEnumerator(action); + } +} \ No newline at end of file diff --git a/src/CatanEngine/CoroutineV2/Core/CoroutineExecutor.ts b/src/CatanEngine/CoroutineV2/Core/CoroutineExecutor.ts new file mode 100644 index 0000000..0ee8409 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/CoroutineExecutor.ts @@ -0,0 +1,103 @@ +import { EnumeratorExecutor } from "./EnumeratorExecutor"; + +export class CoroutineExecutor { + private static _instance: CoroutineExecutor; + static get instance() { + return CoroutineExecutor._instance = CoroutineExecutor._instance || new CoroutineExecutor(); + } + + private _executors: EnumeratorExecutor[] = []; + private _nextExecutors: EnumeratorExecutor[] = []; + private _isRunning: boolean = false; + private _cleanRemoved: boolean = false; + private _scheduler: NodeJS.Timeout; + private _time: number = 0; + + constructor() { + this._time = new Date().getTime(); + // console.debug("[CoroutineV2] Coroutines Start"); + this._scheduler = setInterval(this.update.bind(this), 1 / 60); + } + + StartCoroutine(executor: EnumeratorExecutor) { + executor.next(0); + //TODO: 這邊要考量next後馬上接BaseEnumerator/Iterator的情形 + + if (!this._isRunning) { + this._executors.push(executor); + + if (!this._scheduler) { + // console.debug("[CoroutineV2] Coroutines Start"); + this._time = new Date().getTime(); + this._scheduler = setInterval(this.update.bind(this), 1 / 60); + } else { + // console.debug(`[CoroutineV2] Coroutines add now: ${this._executors.length}`); + } + } else { + this._nextExecutors.push(executor); + } + } + + StopCoroutineBy(target: any) { + if (!target) return; + + for (let r of this._executors) { + if (target === r.target) { + r.Stop(); + } + } + + for (let r of this._nextExecutors) { + if (target === r.target) { + r.Stop(); + } + } + } + + update(delta: number) { + const time: number = new Date().getTime(); + delta = (time - this._time) / 1000; + this._time = time; + if (this._nextExecutors.length) { + this._executors.push(...this._nextExecutors); + // console.debug(`[CoroutineV2] Coroutines addNext now: ${this._executors.length}, next: ${this._nextExecutors.length}`); + this._nextExecutors.length = 0; + } + + if (this._cleanRemoved) { + // 移除[doneFlag=true]的協程 + let index = this._executors.length; + while (index--) { + let r = this._executors[index]; + if (r.doneFlag) { + this._executors.splice(index, 1); + // console.debug(`[CoroutineV2] Coroutines sub now: ${this._executors.length}`); + } + } + this._cleanRemoved = false; + } + + if (this._executors.length == 0) { + console.debug("[CoroutineV2] All Coroutines Done"); + clearInterval(this._scheduler); + this._scheduler = null; + return; + } + + this._isRunning = true; + + // 執行協程 + for (let r of this._executors) { + if (r.doneFlag || r.pauseFlag || r.childFlag) { + if (r.doneFlag) { + this._cleanRemoved = true; + } + continue; + } + + r.next(delta); + } + + this._isRunning = false; + } +} \ No newline at end of file diff --git a/src/CatanEngine/CoroutineV2/Core/EnumeratorExecutor.ts b/src/CatanEngine/CoroutineV2/Core/EnumeratorExecutor.ts new file mode 100644 index 0000000..2506711 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/EnumeratorExecutor.ts @@ -0,0 +1,169 @@ +import { IEnumeratorV2Started } from "../IEnumeratorV2"; +import { BaseEnumerator } from "./BaseEnumerator"; +import { SingleEnumerator } from "./SingleEnumerator"; + +export class EnumeratorExecutor implements IEnumeratorV2Started { + public Current: any; + + public target: any; + public pauseFlag: boolean; + public doneFlag: boolean; + public childFlag: boolean; + public asyncFlag: boolean; + public error: any; + + private _executor: EnumeratorExecutor; + private _enumerator: BaseEnumerator; + + constructor(enumerator: BaseEnumerator, target: any) { + this.target = target; + this._enumerator = enumerator; + } + + next(delta?: any): IteratorResult { + if (this._executor && this._executor.doneFlag) { + this._executor = null; + } + + if (this.doneFlag || (!this._enumerator && !this._executor)) { + this.doneFlag = true; + return { done: true, value: undefined }; + } + + if (this.asyncFlag || this.pauseFlag) return { done: false, value: undefined }; + + let result: IteratorResult; + + if (this._executor) { + result = this._executor.next(delta); + this.Current = this._executor.Current; + if (this._executor.doneFlag) { + this._executor = null; + } else { + result.done = false; + return result; + } + } + + if (!this._enumerator) { + this.doneFlag = true; + return { done: true, value: undefined }; + } + + try { + result = this._enumerator.next(delta); + let value = result.value; + let done = result.done; + + if (value) { + // Iterator + if (typeof value[Symbol.iterator] === 'function') { + value = new SingleEnumerator(>value); + } + + if (value instanceof BaseEnumerator) { + if (!done) { + BaseEnumerator.getLastEnumerator(value).nextEnumerator = this._enumerator; + } + this._enumerator = value; + result = this._enumerator.next(delta); + value = result.value; + done = result.done; + + if (value) { + // Iterator again + if (typeof value[Symbol.iterator] === 'function') { + value = new SingleEnumerator(>value); + } + + if (value instanceof BaseEnumerator) { + if (!done) { + BaseEnumerator.getLastEnumerator(value).nextEnumerator = this._enumerator; + } + this._enumerator = value; + result.done = false; + done = false; + } + } + } + + if (value instanceof EnumeratorExecutor) { + if (done) { + this._enumerator = this._enumerator.nextEnumerator; + } + value.childFlag = true; + result.done = false; + done = false; + this._executor = value; + } else if (Promise.resolve(value) === value) { + this.asyncFlag = true; + result.done = false; + done = false; + (>value) + .then(v => { + this.asyncFlag = false; + this.Current = v; + if (done) { + this._enumerator = this._enumerator.nextEnumerator; + } + }) + .catch(e => { + this.asyncFlag = false; + this.doneFlag = true; + this._enumerator = null; + this.error = e; + if (e instanceof Error) { + cc.error(e.stack); + } else { + cc.error(`Error: ${JSON.stringify(e)}`); + } + }); + } + + this.Current = value; + } + + if (done) { + this._enumerator = this._enumerator.nextEnumerator; + if (this._enumerator) { + result.done = false; + } + } + } + catch (e) + { + this.doneFlag = true; + this.error = e; + if (e instanceof Error) { + cc.error(e.stack); + } else { + cc.error(`Error: ${JSON.stringify(e)}`); + } + result = { done: true, value: e }; + } + + return result; + } + + Stop(): void { + this.doneFlag = true; + if (this._executor) { + this._executor.Stop(); + } + } + + Pause(): void { + this.pauseFlag = true; + if (this._executor) { + this._executor.Pause(); + } + } + + Resume(): void { + this.pauseFlag = false; + if (this._executor) { + this._executor.Resume(); + } + } + +} diff --git a/src/CatanEngine/CoroutineV2/Core/ParallelEnumerator.ts b/src/CatanEngine/CoroutineV2/Core/ParallelEnumerator.ts new file mode 100644 index 0000000..5aa146e --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/ParallelEnumerator.ts @@ -0,0 +1,46 @@ +import { BaseEnumerator } from "./BaseEnumerator"; +import { EnumeratorExecutor } from "./EnumeratorExecutor"; +import { SingleEnumerator } from "./SingleEnumerator"; + +export class ParallelEnumerator extends BaseEnumerator { + private _executors: EnumeratorExecutor[] = []; + + constructor(iterators: Iterator[]) { + super(); + if (iterators && iterators.length) { + for (let iterator of iterators) { + if (iterator instanceof BaseEnumerator) { + this._executors.push(new EnumeratorExecutor(iterator, null)); + } else { + this._executors.push(new EnumeratorExecutor(new SingleEnumerator(iterator), null)); + } + } + } + } + + next(value?: any): IteratorResult { + if (this._executors.length) { + // 先移除[doneFlag=true]協程 + let index = this._executors.length; + while (index--) { + let r = this._executors[index]; + if (r.doneFlag) { + this._executors.splice(index, 1); + } + } + + if (this._executors.length == 0) { + return { done: true, value: undefined }; + } + + // 執行協程 + for (let r of this._executors) { + r.next(value); + } + + return { done: false, value: undefined }; + } + + return { done: true, value: undefined }; + } +} diff --git a/src/CatanEngine/CoroutineV2/Core/SingleEnumerator.ts b/src/CatanEngine/CoroutineV2/Core/SingleEnumerator.ts new file mode 100644 index 0000000..10eae34 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/SingleEnumerator.ts @@ -0,0 +1,18 @@ +import { BaseEnumerator } from "./BaseEnumerator"; + +export class SingleEnumerator extends BaseEnumerator { + private _iterator: Iterator; + + constructor(iterator: Iterator) { + super(); + this._iterator = iterator; + } + + next(value?: any): IteratorResult { + if (!this._iterator) { + return { done: true, value: undefined }; + } + + return this._iterator.next(value); + } +} diff --git a/src/CatanEngine/CoroutineV2/Core/WaitTimeEnumerator.ts b/src/CatanEngine/CoroutineV2/Core/WaitTimeEnumerator.ts new file mode 100644 index 0000000..04d7b2e --- /dev/null +++ b/src/CatanEngine/CoroutineV2/Core/WaitTimeEnumerator.ts @@ -0,0 +1,21 @@ +import { BaseEnumerator } from "./BaseEnumerator"; + +export class WaitTimeEnumerator extends BaseEnumerator { + private _seconds: number; + + constructor(seconds: number) { + super(); + this._seconds = seconds; + } + + next(value?: any): IteratorResult { + let delta = value as number; + this._seconds -= delta; + + if (this._seconds <= 0) { + return { done: true, value: 0 }; + } else { + return { done: false, value: this._seconds }; + } + } +} diff --git a/src/CatanEngine/CoroutineV2/CoroutineV2.ts b/src/CatanEngine/CoroutineV2/CoroutineV2.ts new file mode 100644 index 0000000..5606b57 --- /dev/null +++ b/src/CatanEngine/CoroutineV2/CoroutineV2.ts @@ -0,0 +1,75 @@ +import { IEnumeratorV2, IEnumeratorV2Started } from "./IEnumeratorV2"; +import { BaseEnumerator } from "./Core/BaseEnumerator"; +import { SingleEnumerator } from "./Core/SingleEnumerator"; +import { ParallelEnumerator } from "./Core/ParallelEnumerator"; +import { WaitTimeEnumerator } from "./Core/WaitTimeEnumerator"; +import { ActionEnumerator } from "./Core/ActionEnumerator"; +import { CoroutineExecutor } from "./Core/CoroutineExecutor"; + +export module CoroutineV2 { + /** + * 啟動一般協程 + */ + export function StartCoroutine(iterator: Iterator, target?: any): IEnumeratorV2Started { + return Single(iterator).Start(target); + } + + /** + * 依據IEnumeratorV2.Start(target)綁定的目標, 來停止協程 + * @param target + */ + export function StopCoroutinesBy(target: any) { + CoroutineExecutor.instance.StopCoroutineBy(target); + } + + /** + * 單一協程 + */ + export function Single(iterator: Iterator): IEnumeratorV2 { + if (iterator instanceof BaseEnumerator) { + return iterator; + } else { + return new SingleEnumerator(iterator); + } + } + + /** + * 平行協程 + */ + export function Parallel(...iterators: Iterator[]): IEnumeratorV2 { + return new ParallelEnumerator(iterators); + } + + /** + * 序列協程 + */ + export function Serial(...iterators: Iterator[]): IEnumeratorV2 { + let [iterator, ...others] = iterators; + if (iterator instanceof BaseEnumerator) { + return iterator.ThenSerial(...others); + } else { + return new SingleEnumerator(iterator).ThenSerial(...others); + } + } + + /** + * 執行方法協程 + * @param action 方法 + * @param delaySeconds 延遲秒數 + */ + export function Action(action: Function, delaySeconds?: number): IEnumeratorV2 { + if (delaySeconds > 0) { + return new WaitTimeEnumerator(delaySeconds).Then(new ActionEnumerator(action)); + } else { + return new ActionEnumerator(action); + } + } + + /** + * 等待時間協程 + * @param seconds 秒數 + */ + export function WaitTime(seconds: number): IEnumeratorV2 { + return new WaitTimeEnumerator(seconds); + } +} \ No newline at end of file diff --git a/src/CatanEngine/CoroutineV2/IEnumeratorV2.ts b/src/CatanEngine/CoroutineV2/IEnumeratorV2.ts new file mode 100644 index 0000000..c684c4d --- /dev/null +++ b/src/CatanEngine/CoroutineV2/IEnumeratorV2.ts @@ -0,0 +1,16 @@ +export interface IEnumeratorV2 extends Iterator { + Start(target?: any): IEnumeratorV2Started; + Then(iterator: Iterator): IEnumeratorV2; + ThenSerial(...iterators: Iterator[]): IEnumeratorV2; + ThenParallel(...iterators: Iterator[]): IEnumeratorV2; + ThenAction(action: Function, delaySeconds?: number): IEnumeratorV2; + ThenWaitTime(seconds: number): IEnumeratorV2; +} + +export interface IEnumeratorV2Started { + readonly Current: any; + + Pause(): void; + Resume(): void; + Stop(): void; +} diff --git a/src/NetConnector1.ts b/src/NetConnector1.ts new file mode 100644 index 0000000..95f7150 --- /dev/null +++ b/src/NetConnector1.ts @@ -0,0 +1,6 @@ +// src/electron/NetConnector1.ts +export class NetConnector1 { + constructor() { + console.log("NetConnector instance created"); + } +} diff --git a/src/Utils/CCExtensions/ArrayExtension.ts b/src/Utils/CCExtensions/ArrayExtension.ts new file mode 100644 index 0000000..44199ab --- /dev/null +++ b/src/Utils/CCExtensions/ArrayExtension.ts @@ -0,0 +1,140 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +declare interface Array { + /** + * 移除一個值並且回傳 + * @param index + */ + ExRemoveAt(index: number): T + + /** + * 移除全部值(注意. 參考的也會被清空) + * @example + * + * let bar: number[] = [1, 2, 3]; + * let bar2: number[] = bar; + * bar.Clear(); + * console.log(bar, bar2); + * + * // { + * // "bar": [], + * // "bar2": [] + * // } + */ + Clear(): void + + /** + * 拷貝 + * PS. pass by value 多維陣列也OK + */ + Copy(): T[] + + /** + * 物件陣列排序,asc&key陣列長度請一樣 + * PS. boolean 帶false是先true在false + * @link JavaScript Object 排序 http://www.eion.com.tw/Blogger/?Pid=1170#:~:text=JavaScript%20Object%20排序 + * @param asc 是否升序排列(小到大) + * @param key 需排序的key(優先順序左到右)(沒有就放空) + */ + ObjectSort(asc?: boolean[], key?: string[]): T[] + + /** + * 設計給ArrayforHoldButton使用 + * Add a none persistent listener to the UnityEvent. + * @param call Callback function. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + AddListener(call: Function): void +} + +Array.prototype.ExRemoveAt || + Object.defineProperty(Array.prototype, "ExRemoveAt", { + enumerable: false, + value: function (index: number): any { + const item: any = this.splice(index, 1); + return item[0]; + }, + }); + +Array.prototype.Clear || + Object.defineProperty(Array.prototype, "Clear", { + enumerable: false, + value: function (): void { + this.length = 0; + + // let foo: number[] = [1, 2, 3]; + // let bar: number[] = [1, 2, 3]; + // let foo2: number[] = foo; + // let bar2: number[] = bar; + // foo = []; + // bar.length = 0; + // console.log(foo, bar, foo2, bar2); + + // { + // "foo": [], + // "bar": [], + // "foo2": [ + // 1, + // 2, + // 3 + // ], + // "bar2": [] + // } + }, + }); + +Array.prototype.Copy || + Object.defineProperty(Array.prototype, "Copy", { + enumerable: false, + value: function (): any[] { + return Array.from(this); + }, + }); + +Array.prototype.ObjectSort || + Object.defineProperty(Array.prototype, "ObjectSort", { + enumerable: false, + /** + * @param asc 是否升序排列(小到大) + * @param key 需排序的key(優先順序左到右)(沒有就放空) + */ + value: function (asc: boolean[] = [true], key?: string[]): any[] { + if (this.length === 0) { + return this; + } else if (!key || key.length === 0) { + console.error("ObjectSort key error"); + return this; + } else if (asc.length !== key.length) { + console.error( + `ObjectSort key asc error asc.length: ${asc.length}, key.length: ${key.length}`, + ); + return this; + } + for (let i: number = 0; i < key.length; i++) { + const keyname: string = key[i]; + if (this[0][keyname] === undefined) { + console.error(`ObjectSort has not key[${i}]: ${keyname}`); + return this; + } + } + const count: number = key ? key.length : 1; + let arr: any[]; + for (let i: number = count - 1; i >= 0; i--) { + arr = this.sort(function (a: any, b: any): 1 | -1 { + let mya: any = a; + let myb: any = b; + if (key) { + mya = a[key[i]]; + myb = b[key[i]]; + } + + // 加個等於數字相同不要再去排序到 + if (asc[i]) { + return mya >= myb ? 1 : -1; + } else { + return mya <= myb ? 1 : -1; + } + }); + } + return arr; + }, + }); \ No newline at end of file diff --git a/src/Utils/CCExtensions/NumberExtension.ts b/src/Utils/CCExtensions/NumberExtension.ts new file mode 100644 index 0000000..2da3e6c --- /dev/null +++ b/src/Utils/CCExtensions/NumberExtension.ts @@ -0,0 +1,187 @@ + +declare interface Number { + + /** + * 金額每三位數(千)加逗號, 並且補到小數點第2位 + * 輸出 41,038,560.00 + * @param precision 補到小數點第幾位 + * @param isPadZero 是否要補零 + * */ + ExFormatNumberWithComma(precision?: number, isPadZero?: boolean): string; + /** + * 基本4位數(9,999-999B-T) + * */ + ExTransferToBMK(precision?: number, offset?: number): string; + /** + * 數字轉字串, 頭補0 + * @param size + */ + Pad(size: number): string; + /** + * 四捨五入到小數點第X位 (同server計算規則) + * @param precision + */ + ExToNumRoundDecimal(precision: number): number; + /** + * 無條件捨去到小數點第X位 + * @param precision + */ + ExToNumFloorDecimal(precision: number): number; + /** + * 無條件捨去強制保留X位小數,如:2,會在2後面補上00.即2.00 + * @param precision 補到小數點第幾位 + * @param isPadZero 是否要補零 + */ + ExToStringFloorDecimal(precision: number, isPadZero?: boolean): string; + /** + * 取整數) + */ + ExToInt(): number; + /** + * 小數轉整數(支援科學符號) + */ + Float2Fixed(): number; + /** + * 數字長度(支援科學符號) + */ + DigitLength(): number; + + target: number; + + +} + +Number.prototype.ExFormatNumberWithComma || Object.defineProperty(Number.prototype, 'ExFormatNumberWithComma', { + enumerable: false, + value: function (precision: number, isPadZero: boolean) { + + // let arr = String(this).split('.'); + let arr = this.ExToStringFloorDecimal(precision, isPadZero).split('.'); + let num = arr[0], result = ''; + while (num.length > 3) { + result = ',' + num.slice(-3) + result; + num = num.slice(0, num.length - 3); + } + if (num.length > 0) result = num + result; + return arr[1] ? result + '.' + arr[1] : result; + } +}) + + +Number.prototype.ExTransferToBMK || Object.defineProperty(Number.prototype, 'ExTransferToBMK', { + enumerable: false, + value: function (precision: number, offset: number) { + /**千 */ + let MONEY_1K: number = 1000; + /**萬 */ + // let MONEY_10K: number = 10000; + /**十萬 */ + // let MONEY_100K: number = 100000; + /**百萬 */ + let MONEY_1M: number = 1000000; + /**千萬 */ + // let MONEY_10M: number = 10000000; + /**億 */ + // let MONEY_100M: number = 100000000; + /**十億 */ + let MONEY_1B: number = 1000000000; + /**百億 */ + // let MONEY_10B: number = 10000000000; + /**千億 */ + // let MONEY_100B: number = 100000000000; + /**兆 */ + // let MONEY_1T: number = 1000000000000; + offset = Math.pow(10, offset); + // if (this >= MONEY_1T * offset) { + // //(3)1,000T + // //1T~ + // return (~~(this / MONEY_1T)).ExFormatNumberWithComma(0) + "T"; + // } + if (this >= MONEY_1B * offset) { + //1,000B~900,000B + //1B~900B + return (this / MONEY_1B).ExFormatNumberWithComma(3, false) + "B"; + } + else if (this >= MONEY_1M * offset) { + //1,000M~900,000M + //1M~900M + return (this / MONEY_1M).ExFormatNumberWithComma(3, false) + "M"; + } + else if (this >= MONEY_1K * offset) { + //1,000K~900,000K + //1K~90K + return (this / MONEY_1K).ExFormatNumberWithComma(3, false) + "K"; + } + else { + //0~9,000,000 + //0~9,000 + return this.ExFormatNumberWithComma(precision); + } + } +}) +Number.prototype.Pad || Object.defineProperty(Number.prototype, 'Pad', { + enumerable: false, + value: function (size: number) { + let s = this + ""; + while (s.length < size) s = "0" + s; + return s; + } +}) +Number.prototype.ExToNumRoundDecimal || Object.defineProperty(Number.prototype, 'ExToNumRoundDecimal', { + enumerable: false, + value: function (precision: number) { + return Math.round(Math.round(this * Math.pow(10, (precision || 0) + 1)) / 10) / Math.pow(10, (precision || 0)); + } +}) +Number.prototype.ExToInt || Object.defineProperty(Number.prototype, 'ExToInt', { + enumerable: false, + value: function () { + return ~~this; + } +}) +Number.prototype.ExToNumFloorDecimal || Object.defineProperty(Number.prototype, 'ExToNumFloorDecimal', { + enumerable: false, + value: function (precision: number) { + let str = this.toPrecision(12); + let dotPos = str.indexOf('.'); + return dotPos == -1 ? this : +`${str.substr(0, dotPos + 1 + precision)}`; + } +}) +Number.prototype.ExToStringFloorDecimal || Object.defineProperty(Number.prototype, 'ExToStringFloorDecimal', { + enumerable: false, + value: function (precision: number, isPadZero: boolean) { + // 取小數點第X位 + let f = this.ExToNumFloorDecimal(precision); + let s = f.toString(); + // 補0 + if (isPadZero) { + let rs = s.indexOf('.'); + if (rs < 0) { + rs = s.length; + s += '.'; + } + while (s.length <= rs + precision) { + s += '0'; + } + } + return s; + } +}) +Number.prototype.Float2Fixed || Object.defineProperty(Number.prototype, 'Float2Fixed', { + enumerable: false, + value: function () { + if (this.toString().indexOf('e') === -1) { + return Number(this.toString().replace('.', '')); + } + const dLen = this.DigitLength(); + return dLen > 0 ? +parseFloat((this * Math.pow(10, dLen)).toPrecision(12)) : this; + } +}) +Number.prototype.DigitLength || Object.defineProperty(Number.prototype, 'DigitLength', { + enumerable: false, + value: function () { + const eSplit = this.toString().split(/[eE]/); + const len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0)); + return len > 0 ? len : 0; + } +}) diff --git a/src/Utils/Number/NumberEx.ts b/src/Utils/Number/NumberEx.ts new file mode 100644 index 0000000..c6c841c --- /dev/null +++ b/src/Utils/Number/NumberEx.ts @@ -0,0 +1,180 @@ +import { CoroutineV2 } from "../../CatanEngine/CoroutineV2/CoroutineV2"; +import { RandomEx } from "./RandomEx"; + +export module NumberEx { + /** + * 數字滾動 + * @param startNum 開始 + * @param endNum 結束 + * @param callbackfn 結束回呼 + * @param toInt 是否只顯示整數(預設FALSE) + */ + export function* ChangeScore(startNum: number, endNum: number, callbackfn: (num: number) => void, sec: number, toInt: boolean = true) { + let fps = 30; + let waitTime = 0.03; + let changeRate = sec * fps; + changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1; + changeRate = 1 / changeRate; + let diff = endNum - startNum; + let isIncrease = endNum >= startNum; + let tempScore = startNum; + let counter = 0; + while (true) { + if (endNum != tempScore) { + tempScore += diff * changeRate; + // 遞增 + if (isIncrease && tempScore > endNum) { + tempScore = endNum; + } + // 遞減 + if (!isIncrease && tempScore < endNum) { + tempScore = endNum; + } + if (toInt) { + callbackfn(tempScore.ExToInt()); + } else { + callbackfn(tempScore); + } + counter++; + yield CoroutineV2.WaitTime(waitTime); + } + else { + callbackfn(endNum); + break; + } + } + } + + /** + * 數字跳動(時間內循環EX:1~4=>1.2.3.4.1.2.3.4.1.2.3.4...) + * @param minNum 起始數字 + * @param maxNum 最終數字 + * @param callbackfn callbackfn + * @param sec 時間 + */ + export function* BeatScore(minNum: number, maxNum: number, endNum: number, callbackfn: (num: number) => void, sec: number): IterableIterator { + let fps: number = 13; + let waitTime: number = 0.07; + let changeRate: number = sec * fps; // -1為了讓changeRate數字能混亂點 + changeRate = changeRate - 1 <= 0 ? changeRate : changeRate - 1; + changeRate = 1 / changeRate; + let diff: number = maxNum - minNum; + let isIncrease: boolean = maxNum >= minNum; + let tempScore: number = minNum; + let counter: number = 0; + let randomRate: number = 0; + let lastNum: number = minNum; + let nowNum: number = minNum; + while (true) { + if (maxNum !== tempScore) { + if (counter % 2 === 0) { + if (isIncrease) { + randomRate = RandomEx.GetFloat(0, diff * changeRate).ExToNumFloorDecimal(2); + } else { + randomRate = RandomEx.GetFloat(0, -diff * changeRate).ExToNumFloorDecimal(2); + } + } else { + randomRate = -randomRate; + } + + tempScore += diff * changeRate + randomRate; + // 遞增 + if (isIncrease && tempScore > maxNum) { + tempScore = maxNum; + } + // 遞減 + if (!isIncrease && tempScore < maxNum) { + tempScore = maxNum; + } + while (nowNum === lastNum) { + nowNum = RandomEx.GetInt(minNum, maxNum + 1); + } + lastNum = nowNum; + callbackfn(nowNum); + // yield null; + counter++; + yield CoroutineV2.WaitTime(waitTime); + } else { + callbackfn(endNum); + break; + } + } + } + + /**是否进行边界检查 */ + let _boundaryCheckingState = false; + + /** + * 检测数字是否越界,如果越界给出提示 + * @param {*number} num 输入数 + */ + function checkBoundary(num: number) { + if (_boundaryCheckingState) { + if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) { + console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`); + } + } + } + + /** + * 精确乘法 + */ + export function times(num1: number, num2: number, ...others: number[]): number { + if (others.length > 0) { + return times(times(num1, num2), others[0], ...others.slice(1)); + } + const num1Changed = num1.Float2Fixed(); + const num2Changed = num2.Float2Fixed(); + const baseNum = num1.DigitLength() + num2.DigitLength(); + const leftValue = num1Changed * num2Changed; + + checkBoundary(leftValue); + + return leftValue / Math.pow(10, baseNum); + } + + /** + * 精确加法 + */ + export function plus(num1: number, num2: number, ...others: number[]): number { + if (others.length > 0) { + return plus(plus(num1, num2), others[0], ...others.slice(1)); + } + const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength())); + return (times(num1, baseNum) + times(num2, baseNum)) / baseNum; + } + + /** + * 精确减法 + */ + export function minus(num1: number, num2: number, ...others: number[]): number { + if (others.length > 0) { + return minus(minus(num1, num2), others[0], ...others.slice(1)); + } + const baseNum = Math.pow(10, Math.max(num1.DigitLength(), num2.DigitLength())); + return (times(num1, baseNum) - times(num2, baseNum)) / baseNum; + } + + /** + * 精确除法 + */ + export function divide(num1: number, num2: number, ...others: number[]): number { + if (others.length > 0) { + return divide(divide(num1, num2), others[0], ...others.slice(1)); + } + const num1Changed = num1.Float2Fixed(); + const num2Changed = num2.Float2Fixed(); + checkBoundary(num1Changed); + checkBoundary(num2Changed); + return times((num1Changed / num2Changed), Math.pow(10, num2.DigitLength() - num1.DigitLength())); + } + + /** + * 四舍五入 + */ + export function round(num: number, ratio: number): number { + const base = Math.pow(10, ratio); + return divide(Math.round(times(num, base)), base); + } + +} \ No newline at end of file diff --git a/src/Utils/Number/RandomEx.ts b/src/Utils/Number/RandomEx.ts new file mode 100644 index 0000000..5397f49 --- /dev/null +++ b/src/Utils/Number/RandomEx.ts @@ -0,0 +1,92 @@ +export module RandomEx { + + /** + * 取得隨機布林值 + */ + export function GetBool() { + return GetInt() >= 0; + } + + /** + * 取得隨機整數(回傳min ~ max - 1) + * @param min + * @param max + */ + export function GetInt(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number { + return Math.floor(Math.random() * (max - min)) + min; + } + + /** + * 取得隨機小數 + * @param min + * @param max + */ + export function GetFloat(min: number = Number.MIN_VALUE, max: number = Number.MAX_VALUE): number { + return Math.random() * (max - min) + min; + } + + /** + * 隨機取得複數個不重複回傳 + * @param num 取得數量 + * @param items 陣列 + */ + export function GetMultiNoRepeat(num: number, items: any[]): any[] { + let result: any[] = []; + for (let i: number = 0; i < num; i++) { + let ran: number = Math.floor(Math.random() * items.length); + let item = items.splice(ran, 1)[0]; + if (result.indexOf(item) == -1) { + result.push(item); + } + } + return result; + } + + /** + * 根據權重取得複數個不重複回傳 + * @param prize 獎項 + * @param weights 機率 + * @param count 數量 + */ + export function GetMultiNoRepeatByWeight(prize: any[], weights: number[] = null, count: number = 1): any[] { + if (weights === null) { + weights = []; + for (let i: number = 0; i < prize.length; i++) { + weights.push(1); + } + } + let target: any[] = []; + for (let i: number = 0; i < count; i++) { + let results: number[] = RandomEx.GetPrizeByWeight(prize, weights); + prize.splice(results[0], 1); + weights.splice(results[0], 1); + target.push(results[1]); + } + return target; + } + + + /** + * 根據權重隨機取值 + * @param prize 獎項 + * @param weights 機率 + */ + export function GetPrizeByWeight(prize: any[], weights: number[]): any[] { + if (prize.length !== weights.length) { + console.error(`GetWeight error -> prize.length:${prize.length} !== weights.length:${weights.length}`); + return null; + } + let totalWeight: number = 0; + for (let i: number = 0; i < weights.length; i++) { + totalWeight += weights[i]; + } + let random: number = RandomEx.GetInt(0, totalWeight) + 1; + let nowWeight: number = weights[0]; + for (let i: number = 0; i < weights.length; i++) { + if (nowWeight >= random) { + return [i, prize[i]]; + } + nowWeight += weights[i + 1]; + } + } +} diff --git a/src/Utils/Singleton/BaseSingleton.ts b/src/Utils/Singleton/BaseSingleton.ts new file mode 100644 index 0000000..0533fcf --- /dev/null +++ b/src/Utils/Singleton/BaseSingleton.ts @@ -0,0 +1,27 @@ +/** + * 單例基類(要先new在使用) + * @example + * export default class Test extends BaseSingleton() { ...... } + * new Test(); + * Test.Instance.Init(); + */ +// tslint:disable-next-line:typedef +export default function BaseSingleton() { + class BaseSingleton { + public constructor() { + if ((this)._instance == null) { + BaseSingleton._instance = this; + } + } + public static _instance: BaseSingleton = null; + public static get Instance(): T { + return (this)._instance; + } + + /** 銷毀 */ + public Disp(): void { + (this)._instance = null; + } + } + return BaseSingleton; +} \ No newline at end of file diff --git a/src/Utils/Singleton/BaseSingletonV2.ts b/src/Utils/Singleton/BaseSingletonV2.ts new file mode 100644 index 0000000..29ae821 --- /dev/null +++ b/src/Utils/Singleton/BaseSingletonV2.ts @@ -0,0 +1,28 @@ +/** + * 單例基類 + * @example + * export default class Test extends BaseSigleton() { ...... } + * Test.Instance.Init(); + */ +// tslint:disable-next-line:typedef +export default function BaseSingletonV2() { + class BaseSingleton { + protected constructor() { } + public static _instance: BaseSingleton = null; + public static get Instance(): T { + if ((this)._instance == null) { + (this)._instance = new (this)(); + } + return (this)._instance; + } + + /** 初始化 */ + public Init(): void { /** */ } + + /** 銷毀 */ + public Disp(): void { + (this)._instance = null; + } + } + return BaseSingleton; +} \ No newline at end of file diff --git a/src/Utils/catan.ts b/src/Utils/catan.ts new file mode 100644 index 0000000..574fc81 --- /dev/null +++ b/src/Utils/catan.ts @@ -0,0 +1,16 @@ +// src/Utils/catan.ts +namespace cc { + export function log(msg: string | any, ...subst: any[]): void { + console.log(msg, ...subst); + } + export function warn(msg: string | any, ...subst: any[]): void { + console.warn(msg, ...subst); + } + export function error(msg: string | any, ...subst: any[]): void { + console.error(msg, ...subst); + } +} + +if (!window["cc"]) { + window["cc"] = cc; +} \ No newline at end of file diff --git a/src/api/account/login.ts b/src/api/account/login.ts new file mode 100644 index 0000000..12cb0d5 --- /dev/null +++ b/src/api/account/login.ts @@ -0,0 +1,18 @@ +import { INetRequest } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest"; +import { INetResponse } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; +import { RpcAccountLoginRequest, RpcAccountLoginResponse } from "@/shared/protocols/AccountRequest"; +import { ClientData } from "@/shared/protocols/define/interface"; + +export default function* (clientData: ClientData, req: INetRequest): IterableIterator { + const data: RpcAccountLoginRequest = req.Data + + clientData.name = `test_${clientData.id}`; + clientData.money = 1000000000; + const response: INetResponse = { + Status: 0, + Method: req.Method, + Data: { pr: 2, cu: "TWC", id: clientData.id, name: clientData.name, m: clientData.money }, + IsValid: true + }; + return response; +} \ No newline at end of file diff --git a/src/api/slot/ae.ts b/src/api/slot/ae.ts new file mode 100644 index 0000000..ca2e3dc --- /dev/null +++ b/src/api/slot/ae.ts @@ -0,0 +1,8 @@ +import { INetRequest } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest"; +import { ClientData } from "@/shared/protocols/define/interface"; + +export default function* (clientData: ClientData, req: INetRequest): IterableIterator { + const data = req.Data + + return null; +} \ No newline at end of file diff --git a/src/api/slot/in.ts b/src/api/slot/in.ts new file mode 100644 index 0000000..8e978af --- /dev/null +++ b/src/api/slot/in.ts @@ -0,0 +1,16 @@ +import { INetRequest } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest"; +import { INetResponse } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; +import { ClientData } from "@/shared/protocols/define/interface"; +import { RpcSlotInRequest, RpcSlotInResponse } from "@/shared/protocols/SlotRequest"; + +export default function* (clientData: ClientData, req: INetRequest): IterableIterator { + const data: RpcSlotInRequest = req.Data + + const response: INetResponse = { + Status: 0, + Method: req.Method, + Data: { ver: "", db: 4, br: [4, 10, 20, 40, 80, 100, 120, 160, 200, 400, 600, 800, 1000, 1200, 1600, 2000, 4000, 10000, 20000, 30000], jp: { "1": 1500000, "3": 3000000, "5": 30000000 } }, + IsValid: true + }; + return response; +} \ No newline at end of file diff --git a/src/api/slot1/fgspin.ts b/src/api/slot1/fgspin.ts new file mode 100644 index 0000000..be257a9 --- /dev/null +++ b/src/api/slot1/fgspin.ts @@ -0,0 +1,28 @@ +import { INetRequest } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest"; +import { INetResponse } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; +import { ClientData } from "@/shared/protocols/define/interface"; +import { RpcSlot1SpinRequest, RpcSlot1SpinResponse } from "@/shared/protocols/Slot1Request"; +import { RandomEx } from "@/Utils/Number/RandomEx"; + +export default function* (clientData: ClientData, req: INetRequest): IterableIterator { + const data: RpcSlot1SpinRequest = req.Data + + const temps: string[] = [ + `{"slot":[11,4,8,9,5,2,13,10,7,9,10,6,6,12,4],"line":[[[5,11,12],161,2000]],"get":[[1,2000]]}`, + + `{"slot":[9,6,2,5,4,14,10,9,13,10,4,5,5,2,2]}`, + + `{"slot":[4,3,3,3,9,10,14,14,9,4,7,8,8,5,10],"free":[[1,2,3],3],"scatter":[[[1,2,3],3000]],"get":[[1,2000]]}`, + ]; + const Data: any = JSON.parse(temps[RandomEx.GetInt(0, temps.length)]); + Data["pay"] = [[1, -data.pay]]; + Data["money"] = 9991304; + + const response: INetResponse = { + Status: 0, + Method: req.Method, + Data, + IsValid: true + }; + return response; +} \ No newline at end of file diff --git a/src/api/slot1/spin.ts b/src/api/slot1/spin.ts new file mode 100644 index 0000000..f2ecfa6 --- /dev/null +++ b/src/api/slot1/spin.ts @@ -0,0 +1,32 @@ +import { INetRequest } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest"; +import { INetResponse } from "@/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; +import { ClientData } from "@/shared/protocols/define/interface"; +import { RpcSlot1SpinRequest, RpcSlot1SpinResponse } from "@/shared/protocols/Slot1Request"; +import { RandomEx } from "@/Utils/Number/RandomEx"; + +export default function* (clientData: ClientData, req: INetRequest): IterableIterator { + const data: RpcSlot1SpinRequest = req.Data + + const temps: string[] = [ + `{"slot":[11,4,8,9,5,2,13,10,7,9,10,6,6,12,4],"line":[[[5,11,12],161,2000]],"get":[[1,2000]]}`, + + `{"slot":[9,6,2,5,4,14,10,9,13,10,4,5,5,2,2]}`, + + // `{"slot":[4,3,3,3,9,10,14,14,9,4,7,8,8,5,10],"free":[[1,2,3],3],"scatter":[[[1,2,3],3000]],"get":[[1,2000]]}`, + ]; + const Data: any = JSON.parse(temps[RandomEx.GetInt(0, temps.length)]); + clientData.money -= data.pay; + if (Data.get) { + clientData.money += Data.get[0][1]; + } + Data["pay"] = [[1, -data.pay]]; + Data["money"] = clientData.money; + + const response: INetResponse = { + Status: 0, + Method: req.Method, + Data, + IsValid: true + }; + return response; +} \ No newline at end of file diff --git a/src/electron/main.ts b/src/electron/main.ts index d6e55d5..ecb9eb2 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -1,11 +1,24 @@ -// src/main.ts +// src/electron/main.ts +// 需要先載入 +import "module-alias/register"; + +// // 必載入 +// import "../Utils/catan.ts"; + +import { BaseEnumerator } from "@/CatanEngine/CoroutineV2/Core/BaseEnumerator"; +import { NetConnector } from "@/script/Engine/CatanEngine/NetManagerV2/NetConnector"; import dotenv from 'dotenv'; import { app, BrowserWindow, ipcMain } from 'electron'; import * as path from 'path'; import { WebSocketServer } from 'ws'; -// Load environment variables from .env file -dotenv.config(); +onload(); + +function onload() { + BaseEnumerator.Init(); + // Load environment variables from .env file + dotenv.config(); +} let server: WebSocketServer | null = null; let port: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080; // 默认端口为 8080 @@ -31,21 +44,6 @@ function createWindow() { let mainWindow: BrowserWindow | null = null; -// Create a function to send log messages to the renderer -function sendLogToRenderer(window: BrowserWindow, message: string) { - window.webContents.send('log-message', message); -} - -// 重寫 console.log 方法以便將訊息發送到渲染進程 -const originalConsoleLog = console.log; -console.log = (...args: any[]) => { - const message = args.join(' '); - originalConsoleLog(message); // 保留原始行為 - if (BrowserWindow.getAllWindows().length > 0) { - sendLogToRenderer(BrowserWindow.getAllWindows()[0], message); // 發送訊息到渲染進程 - } -}; - app.whenReady().then(() => { mainWindow = createWindow(); @@ -72,21 +70,23 @@ ipcMain.on('start-websocket', (event, portNumber: number) => { server = new WebSocketServer({ port: port }); - server.on('connection', (socket, request) => { - const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP'; - console.log(`Client connected from IP: ${ip}`); - socket.send('Welcome to the WebSocket server'); + server.on('connection', NetConnector.OnWebSocketConnection); - socket.on('message', (message: string) => { - console.log(`[RPC] 收到client呼叫: ${message}`); - socket.send(`Server received your message: ${message}`); - console.log(`[RPC] 回傳client呼叫: ${message}`); - }); + // server.on('connection', (socket, request) => { + // const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP'; + // console.log(`Client connected from IP: ${ip}`); + // socket.send('Welcome to the WebSocket server'); - socket.on('close', () => { - console.log('Client disconnected'); - }); - }); + // socket.on('message', (message: string) => { + // console.log(`[RPC] 收到client呼叫: ${message}`); + // socket.send(`Server received your message: ${message}`); + // console.log(`[RPC] 回傳client呼叫: ${message}`); + // }); + + // socket.on('close', () => { + // console.log('Client disconnected'); + // }); + // }); event.reply('websocket-status', `WebSocket server started on port ${port}`); }); @@ -114,4 +114,39 @@ ipcMain.on('stop-websocket', (event) => { // 打开开发者工具 ipcMain.on('open-devtools', () => { mainWindow.webContents.openDevTools(); -}); \ No newline at end of file +}); + +// Create a function to send log messages to the renderer +function sendLogToRenderer(window: BrowserWindow, message: string, color: string) { + window.webContents.send('log-message', [message, color]); +} + +// 重寫 console.log 方法以便將訊息發送到渲染進程 +const originalConsoleLog = console.log; +console.log = (...args: any[]) => { + const message = args.join(' '); + originalConsoleLog(message); // 保留原始行為 + if (BrowserWindow.getAllWindows().length > 0) { + sendLogToRenderer(BrowserWindow.getAllWindows()[0], message, "green"); // 發送訊息到渲染進程 + } +}; + +// 重写 console.warn +const originalConsoleWarn = console.warn; +console.warn = (...args: any[]) => { + const message = args.join(' '); + originalConsoleWarn(message); + if (BrowserWindow.getAllWindows().length > 0) { + sendLogToRenderer(BrowserWindow.getAllWindows()[0], message, "yellow"); // 發送訊息到渲染進程 + } +}; + +// 重写 console.error +const originalConsoleError = console.error; +console.error = (...args: any[]) => { + const message = args.join(' '); + originalConsoleError(message); + if (BrowserWindow.getAllWindows().length > 0) { + sendLogToRenderer(BrowserWindow.getAllWindows()[0], message, "red"); // 發送訊息到渲染進程 + } +}; \ No newline at end of file diff --git a/src/electron/preload.ts b/src/electron/preload.ts index 44a1782..ececf4d 100644 --- a/src/electron/preload.ts +++ b/src/electron/preload.ts @@ -1,12 +1,13 @@ -// src/preload.ts +// src/electron/preload.ts import { contextBridge, ipcRenderer } from 'electron'; +// import "../Utils/catan"; // 导入定义全局 cc 对象的文件 contextBridge.exposeInMainWorld('electron', { startWebSocket: (port: number) => ipcRenderer.send('start-websocket', port), stopWebSocket: () => ipcRenderer.send('stop-websocket'), openDevTools: () => ipcRenderer.send('open-devtools'), onWebSocketStatus: (callback: (message: string) => void) => ipcRenderer.on('websocket-status', (event, message) => callback(message)), - onLogMessage: (callback: (message: string) => void) => ipcRenderer.on('log-message', (event, message) => callback(message)), + onLogMessage: (callback: (message: string, color: string) => void) => ipcRenderer.on('log-message', (event, [message, color]) => callback(message, color)), env: { PORT: process.env.PORT || '8080' // 提供環境變數 } diff --git a/src/electron/renderer.ts b/src/electron/renderer.ts index f954661..4ae290d 100644 --- a/src/electron/renderer.ts +++ b/src/electron/renderer.ts @@ -1,3 +1,4 @@ +// src/electron/renderer.ts const maxLogs = 200; // 设置最大日志数量 const logs: string[] = []; @@ -5,9 +6,9 @@ const logs: string[] = []; // 格式化时间戳的函数 function formatDate(date: Date): string { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始 - const day = String(date.getDate()).padStart(2, '0'); + // const year = date.getFullYear(); + // const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始 + // const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); @@ -19,14 +20,14 @@ function formatDate(date: Date): string { function updateLogDisplay() { const logContainer = document.getElementById('log') as HTMLElement; if (logContainer) { - logContainer.innerText = logs.join('\n'); + logContainer.innerHTML = logs.join(''); // 使用 innerHTML 来渲染带有样式的日志 logContainer.scrollTop = 0; // 保持滚动位置在顶部 } } -function addLog(message: string) { +function addLog(message: string, color: string = 'green') { const timestamp = formatDate(new Date()); // 使用当前时间生成时间戳 - const logMessage = `[${timestamp}] ${message}`; // 在日志消息前添加时间戳 + const logMessage = `
[${timestamp}] ${message}
`; // 在日志消息前添加时间戳,并设置颜色 logs.unshift(logMessage); // 在数组开头插入新消息 @@ -69,6 +70,6 @@ window.electron.onWebSocketStatus((message: string) => { }); // 监听主进程发送的日志消息 -window.electron.onLogMessage((message: string) => { - addLog(message); // 將日誌消息添加到顯示區 +window.electron.onLogMessage((message: string, color: string) => { + addLog(message, color); // 將日誌消息添加到顯示區 }); \ No newline at end of file diff --git a/src/global.d.ts b/src/global.d.ts index ea3c59e..5ec2625 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -5,7 +5,7 @@ interface Window { stopWebSocket: () => void; openDevTools: () => void; onWebSocketStatus: (callback: (message: string) => void) => void; - onLogMessage: (callback: (message: string) => void) => void; // 添加這行以處理日誌消息 + onLogMessage: (callback: (message: string, color: string) => void) => void; // 添加這行以處理日誌消息 env: { PORT: string; }; }; } diff --git a/src/pkg/server.ts b/src/pkg/server.ts index 62d6ff8..8ca321c 100644 --- a/src/pkg/server.ts +++ b/src/pkg/server.ts @@ -1,5 +1,18 @@ +// src/pkg/server.ts +// 需要先載入 +import "module-alias/register"; + +// // 必載入 +// import "../Utils/catan.ts"; + import WebSocket, { WebSocketServer } from 'ws'; +/* +http://entry.lybobet.com/casino_sd_2/resource-internal/_Debug/slot1/index.html?token=test&slotid=1&v=1724652287&host=127.0.0.1&language=zh-tw&logo=2&pl=1 +ws://192.168.5.36:9005 +ws://127.0.0.1:9005 +*/ + const server = new WebSocketServer({ port: 8080 }); server.on('connection', (socket: WebSocket) => { diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts new file mode 100644 index 0000000..07b0e58 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts @@ -0,0 +1,13 @@ + +import { Action } from "../../../../../CatanEngine/CSharp/System/Action"; +import { INetResponse } from "./INetResponse"; + +export interface INetConnector { + readonly OnDataReceived: Action>; + readonly OnDisconnected: Action; + readonly IsConnected: boolean; + + // SendAsync(req: INetRequest): Iterator; + // Send(req: INetRequest); + // Logout(); +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts.meta b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts.meta new file mode 100644 index 0000000..8f7c43c --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetConnector.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "f97991b5-0da6-4220-ab29-13c8f8f7e405", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts new file mode 100644 index 0000000..1a72c41 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts @@ -0,0 +1,17 @@ +export interface INetRequest { + readonly Method: string; + readonly Data: TResponse; +} + +// import { INetResponse } from "./INetResponse"; + +// export interface INetRequest { +// readonly Method: string; +// readonly MethodBack: string; + +// Data: TRequest; +// Result: INetResponse; + +// SendAsync(): Iterator; +// Send(); +// } \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts.meta b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts.meta new file mode 100644 index 0000000..af38d71 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetRequest.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "339fcf27-bdb9-4b8f-ae18-dd54c9500145", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts new file mode 100644 index 0000000..502b4cf --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts @@ -0,0 +1,6 @@ +export interface INetResponse { + readonly Method: string; + readonly Status: number; + readonly Data: TResponse; + readonly IsValid: boolean; +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts.meta b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts.meta new file mode 100644 index 0000000..cf97e1f --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/Core/INetResponse.ts.meta @@ -0,0 +1,10 @@ +{ + "ver": "1.1.0", + "uuid": "c4cb0cd4-b98c-4f8e-b1e6-ac3b51281b28", + "importer": "typescript", + "isPlugin": false, + "loadPluginInWeb": true, + "loadPluginInNative": true, + "loadPluginInEditor": false, + "subMetas": {} +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/NetConfig.ts b/src/script/Engine/CatanEngine/NetManagerV2/NetConfig.ts new file mode 100644 index 0000000..f367907 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/NetConfig.ts @@ -0,0 +1,4 @@ +export default class NetConfig { + /**是否顯示RPC接送JSON的LOG */ + public static ShowServerLog: boolean = true; +} \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/NetConnector.ts b/src/script/Engine/CatanEngine/NetManagerV2/NetConnector.ts new file mode 100644 index 0000000..ee32ff2 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/NetConnector.ts @@ -0,0 +1,149 @@ +import { CoroutineV2 } from "@/CatanEngine/CoroutineV2/CoroutineV2"; +import { Encoding } from "@/CatanEngine/CSharp/System/Text/Encoding"; +import { ClientData } from "@/shared/protocols/define/interface"; +import { IncomingMessage } from "http"; +import { WebSocket } from "ws"; +import { Action } from "../../../../CatanEngine/CSharp/System/Action"; +import { INetRequest } from "./Core/INetRequest"; +import { INetResponse } from "./Core/INetResponse"; + +let id = 1; + +export class NetConnector { + readonly OnDataReceived: Action> = new Action>(); + readonly OnDisconnected: Action = new Action(); + readonly OnLoadUIMask: Action = new Action(); + public static readonly clients = new Map(); + + public static OnWebSocketConnection(socket: WebSocket, request: IncomingMessage) { + const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP'; + console.log(`Client connected from IP: ${ip}`); + + NetConnector.clients.set(socket, { socket, id: id, name: "", money: 0 }); + id++; + + socket.on('message', (message: Buffer) => NetConnector.OnWebSocketMessage(socket, message)); + + socket.on('close', NetConnector.OnWebSocketClose); + } + + public static async OnWebSocketMessage(socket: WebSocket, message: Buffer) { + // 将 Buffer 转换为 ArrayBuffer + const buffer = message.buffer.slice(message.byteOffset, message.byteOffset + message.byteLength); + let startIndex = 0, byteLength = buffer.byteLength; + while (startIndex + 4 < byteLength) { + const view: DataView = new DataView(buffer, 0, 3); + const strlen: number = view.getUint16(0, true) + (view.getUint8(2) << 16); + const decoder: TextDecoder = new TextDecoder("utf-8"); + const str: string = decoder.decode(new Uint8Array(buffer, startIndex + 4, strlen)); + startIndex += strlen + 4; + + // try { + let json = JSON.parse(str); + let method = json[0]; + let data = json[1]; + + let req = >{ + Method: method, + Data: data, + }; + + if (data) { + console.log(`[RPC] 收到client呼叫: ${req.Method}(${JSON.stringify(req.Data)})`); + } else { + console.log(`[RPC] 收到client呼叫: ${req.Method}()`); + } + + // 动态导入处理函数 + try { + // 动态导入文件 + const module = await import(`@/api/${req.Method.replace(".", "/")}`); + + // 调用导入模块中的处理函数 + if (module.default) { + let AsyncFunction: () => IterableIterator = function* (): IterableIterator { + const clientData: ClientData = NetConnector.clients.get(socket); + const response: INetResponse = yield* module.default(clientData, req); + if (response) { + NetConnector.Send(socket, response); + } + }; + CoroutineV2.Single(AsyncFunction()).Start(); + } else { + throw new Error(`Module for ${req.Method} does not export a default function.`); + } + } catch (error) { + console.error(`Error handling request ${req.Method}: ${error.message}`); + const response: INetResponse = { + Status: -1, + Method: req.Method, + Data: null, + IsValid: false + }; + NetConnector.Send(socket, response); + } + + // const module = await import(`@/api/${req.Method.replace(".", "/")}`); + // if (module) { + // let AsyncFunction: () => IterableIterator = function* (): IterableIterator { + // const response: INetResponse = yield* module.default(req); + // NetConnector.Send(socket, response); + // }; + // CoroutineV2.Single(AsyncFunction()).Start(); + // } else { + // const response: INetResponse = { + // Status: -1, + // Method: req.Method, + // Data: null, + // IsValid: false + // }; + // NetConnector.Send(socket, response); + // } + + // } catch (e) { + // console.error(e); + // throw new Error(`[RPC] 無法解析Server回應: ${str}`); + // } + } + } + + public static OnWebSocketClose() { + console.log('Client disconnected'); + } + + private static Send(socket: WebSocket, resp: INetResponse) { + let json: any = [resp.Method, [resp.Status]]; + //@ts-ignore + if (resp.Data != null && resp.Data != undefined && resp.Data != NaN) { + json[1].push(resp.Data); + } + + //@ts-ignore + if (resp.Data != null && resp.Data != undefined && resp.Data != NaN) { + console.log(`[RPC] 回傳client呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); + } else { + console.log(`[RPC] 回傳client呼叫:(${resp.Status}): ${resp.Method}()`); + } + + let str = JSON.stringify(json); + if (str.length > 65535) { + throw new Error("要傳的資料太大囉"); + } + + let strary = Encoding.UTF8.GetBytes(str); + let buffer = new Uint8Array(4 + strary.byteLength); + let u16ary = new Uint16Array(buffer.buffer, 0, 3); + u16ary[0] = strary.byteLength; + buffer[3] = 0x01; + buffer.set(strary, 4); + + socket.send(buffer); + } +} + +const ErrorResponse: INetResponse = { + Status: -1, + Method: "", + Data: {}, + IsValid: false +}; \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/NetManager.ts b/src/script/Engine/CatanEngine/NetManagerV2/NetManager.ts new file mode 100644 index 0000000..81eabf2 --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/NetManager.ts @@ -0,0 +1,53 @@ +// import { INetRequest } from "./Core/INetRequest"; +// import { NetConnector } from "./NetConnector"; + +// export class NetManager { +// static get IsConnected() { return this._connector && this._connector.IsConnected; } +// static get HasInit() { return this._connector != null; } + +// private static _connector: NetConnector; + +// static Initialize(connector: NetConnector) { +// this._connector = connector; +// } + +// static ConnectAsync() { +// this.CheckConnector(); +// return this._connector.ConnectAsync(); +// } + +// /** +// * 斷線 +// */ +// static Disconnect() { +// this.CheckConnector(); +// this._connector.Disconnect(); +// } + +// /** +// * 傳送資料給Server, 不等待回應 +// * @param req +// */ +// static Send(req: INetRequest) { +// this.CheckConnector(); +// if (NativeClass.IsLineProject) { +// NativeClass.Instance.GetSend(req); +// } else { +// this._connector.Send(req); +// } +// } + +// /** +// * 傳送資料給Server, 並等待回應 +// * @param req +// */ +// static SendAsync(req: INetRequest, mask: boolean) { +// this.CheckConnector(); +// return this._connector.SendAsync(req, mask); +// } + +// private static CheckConnector() { +// if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector"); +// } + +// } \ No newline at end of file diff --git a/src/script/Engine/CatanEngine/NetManagerV2/NetRequest.ts b/src/script/Engine/CatanEngine/NetManagerV2/NetRequest.ts new file mode 100644 index 0000000..8fc8dfa --- /dev/null +++ b/src/script/Engine/CatanEngine/NetManagerV2/NetRequest.ts @@ -0,0 +1,21 @@ +// import { INetRequest } from "./Core/INetRequest"; +// import { NetManager } from "./NetManager"; + +// export abstract class NetRequest implements INetRequest { +// abstract get Method(): string; + +// get MethodBack(): string { +// return this.Method; +// } + +// Data: TResquest; +// Result: import("./Core/INetResponse").INetResponse; + +// SendAsync(mask: boolean = false): Iterator { +// return NetManager.SendAsync(this, mask); +// } + +// Send() { +// NetManager.Send(this); +// } +// } diff --git a/src/shared/.gitkeep b/src/shared/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/shared/protocols/AccountRequest.ts b/src/shared/protocols/AccountRequest.ts new file mode 100644 index 0000000..15838ae --- /dev/null +++ b/src/shared/protocols/AccountRequest.ts @@ -0,0 +1,6 @@ +// #region Request + +export type RpcAccountLoginRequest = { token: string } +export type RpcAccountLoginResponse = { "pr": number, "cu": string, "id": number, "name": string, "m": number } + +// #endregion \ No newline at end of file diff --git a/src/shared/protocols/Slot1Request.ts b/src/shared/protocols/Slot1Request.ts new file mode 100644 index 0000000..05cdfa8 --- /dev/null +++ b/src/shared/protocols/Slot1Request.ts @@ -0,0 +1,6 @@ +// #region Request + +export type RpcSlot1SpinRequest = { pay: number } +export type RpcSlot1SpinResponse = { slot: number[], pay: number[][], money: number } + +// #endregion \ No newline at end of file diff --git a/src/shared/protocols/SlotRequest.ts b/src/shared/protocols/SlotRequest.ts new file mode 100644 index 0000000..66aa77f --- /dev/null +++ b/src/shared/protocols/SlotRequest.ts @@ -0,0 +1,6 @@ +// #region Request + +export type RpcSlotInRequest = { id: number } +export type RpcSlotInResponse = { "ver": string, "db": number, "br": number[], "jp": { [key: string]: number } } + +// #endregion \ No newline at end of file diff --git a/src/shared/protocols/define/enum.ts b/src/shared/protocols/define/enum.ts new file mode 100644 index 0000000..444bad4 --- /dev/null +++ b/src/shared/protocols/define/enum.ts @@ -0,0 +1,4 @@ +// export enum EGameState { +// /** 準備 */ +// Ready, +// } \ No newline at end of file diff --git a/src/shared/protocols/define/interface.ts b/src/shared/protocols/define/interface.ts new file mode 100644 index 0000000..47188ba --- /dev/null +++ b/src/shared/protocols/define/interface.ts @@ -0,0 +1,9 @@ +import { WebSocket } from "ws"; + +// ClientData +export interface ClientData { + socket: WebSocket; + id: number; + name: string; + money: number; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 967f969..e70f170 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,25 @@ { "compilerOptions": { - "target": "ES2020", // 设置 ECMAScript 版本 - "module": "CommonJS", // 使用 CommonJS 模块系统 + "module": "commonjs", // 使用 CommonJS 模块系统 + "target": "es2015", // 编译为 ES2015 + "moduleResolution": "node", "sourceMap": true, "strict": false, // 启用严格模式 "esModuleInterop": true, // 启用 ES 模块的兼容性 "skipLibCheck": true, // 跳过库的类型检查 "forceConsistentCasingInFileNames": true, + "baseUrl": ".", "paths": { - "@/*": [ - "./src/*" - ] + "@/*": ["src/*"] }, "outDir": "./dist", "rootDir": "./src", }, - "include": ["src/**/*"] // 包含 src 目录下的所有文件 + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules" // 排除 node_modules 目录 + ] } \ No newline at end of file diff --git a/tsrpc.config.ts b/tsrpc.config.ts new file mode 100644 index 0000000..8d45a32 --- /dev/null +++ b/tsrpc.config.ts @@ -0,0 +1,38 @@ +import type { TsrpcConfig } from "tsrpc-cli"; + +export default { + // Generate ServiceProto + proto: [ + { + ptlDir: "src/shared/protocols", // Protocol dir + output: "src/shared/protocols/serviceProto.ts", // Path for generated ServiceProto + apiDir: "src/api", // API dir + docDir: "docs", // API documents dir + ptlTemplate: { baseFile: "src/shared/protocols/base.ts" }, + // msgTemplate: { baseFile: 'src/shared/protocols/base.ts' }, + } + ], + // Sync shared code + sync: [ + { + from: "src/shared", + // to: "../GuessWhoIAm/src/shared", + type: "copy" // Change this to 'copy' if your environment not support symlink + } + ], + // Dev server + dev: { + autoProto: true, // Auto regenerate proto + autoSync: true, // Auto sync when file changed + autoApi: true, // Auto create API when ServiceProto updated + watch: "src", // Restart dev server when these files changed + entry: "src/index.ts", // Dev server command: node -r ts-node/register {entry} + }, + // Build config + build: { + autoProto: true, // Auto generate proto before build + autoSync: true, // Auto sync before build + autoApi: true, // Auto generate API before build + outDir: "dist", // Clean this dir before build + } +}; \ No newline at end of file