[add] First

This commit is contained in:
建喵 2022-07-26 14:09:04 +08:00
commit 4804fc1005
137 changed files with 9335 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["johnsoncodehk.volar"]
}

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# Vue 3 + Typescript + Vite
1. npm install
2. npm run dev
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
## Type Support For `.vue` Imports in TS
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

18
index.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<link href="./src/assets/ZenMaruGothic-Regular.ttf" rel="stylesheet">
<!-- <link href="https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic&display=swap" rel="stylesheet"> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BJ_ServerState</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3162
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "bj-casino-rank",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"@popperjs/core": "^2.11.5",
"axios": "^0.26.1",
"bootstrap": "^5.1.3",
"element-plus": "^2.1.9",
"moment": "^2.29.2",
"vue": "^3.2.25",
"vue-loading-overlay": "^5.0.3"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.0",
"typescript": "^4.5.4",
"vite": "^2.9.0",
"vue-tsc": "^0.29.8"
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

20
public/index.html Normal file
View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="./assets/favicon.69a65d1f.ico" />
<link href="./src/assets/ZenMaruGothic-Regular.ttf" rel="stylesheet">
<!-- <link href="https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic&display=swap" rel="stylesheet"> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BJ_ServerState</title>
<script type="module" crossorigin src="./assets/index.59c18d08.js"></script>
<link rel="stylesheet" href="./assets/index.b312efde.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

56
src/App.vue Normal file
View File

@ -0,0 +1,56 @@
<script setup lang="ts">
import { ref } from 'vue';
import 'vue-loading-overlay/dist/vue-loading.css';
import BJ_ServerState from './components/BJ_ServerState.vue';
import { BJ_Casino_Data } from './script/BJ_Casino_Data';
const self = {}
let Title = ref("BJ_ServerState");
const BJ_Casino = new BJ_Casino_Data(self)
</script>
<template>
<h1>
{{ Title }}
</h1>
<div class="d-flex justify-content-center">
<table class="table table-striped table-info table-hover">
<thead>
<tr>
<th align="left">名稱</th>
<th align="left">Host</th>
<th align="left">Port</th>
<th align="left">狀態</th>
</tr>
</thead>
<tbody v-for="(item, index) in BJ_Casino.Config.ServerList" :key="index">
<BJ_ServerState :BJ_Casino="BJ_Casino" :ID=index />
</tbody>
<!-- <BJ_ServerState :BJ_Casino="BJ_Casino" :ID=0 /> -->
</table>
</div>
</template>
<style>
@import url('../src/assets/fonts.css');
@import url('../src/assets/style.css');
.el-tabs__nav {
float: none;
}
.el-tabs__item {
font-size: 18px;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 0px;
font-family: 'Zen Maru Gothic', sans-serif;
}
</style>

49
src/assets/config.json Normal file
View File

@ -0,0 +1,49 @@
{
"ServerList": [
{
"name": "內版",
"host": "http://220.134.195.1",
"port": "19005"
},
{
"name": "肉乾 9006",
"host": "http://192.168.5.230",
"port": "9006"
},
{
"name": "肉乾 9007",
"host": "http://192.168.5.230",
"port": "9007"
},
{
"name": "40 9487",
"host": "http://192.168.5.12",
"port": "9487"
},
{
"name": "送審",
"host": "https://submit.online-bj.com",
"port": "9005"
},
{
"name": "外版",
"host": "https://game.online-bj.com",
"port": "9005"
},
{
"name": "testing1",
"host": "http://bj-testing1.casino.catan.com.tw",
"port": "9005"
},
{
"name": "testing2",
"host": "http://bj-testing2.casino.catan.com.tw",
"port": "9005"
},
{
"name": "testing3",
"host": "http://bj-testing3.casino.catan.com.tw",
"port": "9005"
}
]
}

7
src/assets/fonts.css Normal file
View File

@ -0,0 +1,7 @@
@font-face {
/* 重命名字体名 */
font-family: 'Zen Maru Gothic';
src: url('./fonts/ZenMaruGothic-Regular.ttf');
font-weight: normal;
font-style: normal;
}

Binary file not shown.

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

8
src/assets/style.css Normal file
View File

@ -0,0 +1,8 @@
.table {
width: inherit;
}
.el-tabs__nav-scroll {
/* width: 50%; */
margin: 0 auto;
}

View File

@ -0,0 +1,4 @@
.xyhot {
width: auto;
overflow-y: hidden;
}

View File

@ -0,0 +1,4 @@
.xyhot {
width: auto;
overflow-y: hidden;
}

View File

@ -0,0 +1,4 @@
.xyhot {
width: 100%;
overflow-y: hidden;
}

View File

@ -0,0 +1,4 @@
/* .xyhot {
width: auto;
overflow-y: hidden;
} */

View File

@ -0,0 +1,39 @@
<script setup lang="ts">
import { ref } from "vue";
import { BJ_Casino_Data } from "../script/BJ_Casino_Data";
import { BJ_ServerState } from "../script/BJ_ServerState";
const props = defineProps<{ BJ_Casino: BJ_Casino_Data, ID: number }>()
let Name = ref("");
let Host = ref("");
let Port = ref("");
let IsConnect = ref("false");
const self = {
ID: props.ID,
BJ_Casino: props.BJ_Casino,
Name: Name,
Host: Host,
Port: Port,
IsConnect: IsConnect,
}
const Script = new BJ_ServerState(self);
</script>
<template>
<tr>
<td>
<font size="5"><b>{{ Name }}</b></font>
</td>
<td>
<font size="5"><b>{{ Host }}</b></font>
</td>
<td>
<font size="5"><b>{{ Port }}</b></font>
</td>
<td>
<font size="5"><b>{{ IsConnect }}</b></font>
</td>
</tr>
</template>

8
src/env.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}

11
src/main.ts Normal file
View File

@ -0,0 +1,11 @@
import '@popperjs/core';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import locale from 'element-plus/lib/locale/lang/zh-tw';
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).use(ElementPlus, { locale }).mount('#app')

View File

@ -0,0 +1,29 @@
import config from '../../src/assets/config.json';
import "./Engine/CatanEngine/CSharp/String";
export class BJ_Casino_Data {
//#region public
public Client: any;
public Config: any;
//#endregion
//#region Lifecycle
/**
*
*/
constructor(client: any) {
this.Client = client;
this.onLoad();
}
public async onLoad(): Promise<void> {
this.Config = config;
}
//#endregion
}

View File

@ -0,0 +1,124 @@
import { BJ_Casino_Data } from "./BJ_Casino_Data";
import { NetConnector } from "./Engine/CatanEngine/NetManagerV2/NetConnector";
import { Tools } from "./Tools";
export class BJ_ServerState {
//#region Lifecycle
public BJ_Casino: BJ_Casino_Data;
public ID: number;
//#endregion
//#region private
private _conn: NetConnector = null;
private _client: any;
//#endregion
//#region Lifecycle
/**
*
*/
constructor(client: any) {
this._client = client;
this.BJ_Casino = client.BJ_Casino;
this.ID = client.ID;
this.onLoad();
}
public async onLoad(): Promise<void> {
await this.ConnectServer();
}
//#endregion
//#region 網路相關
/** 連線 */
public async ConnectServer(): Promise<void> {
let serverList = this.BJ_Casino.Config.ServerList;
let server = serverList[this.ID];
if (!server) {
return;
}
const Name: string = server.name;
const Host: string = server.host;
const Port: string = server.port;
this._client.Name.value = Name;
this._client.Host.value = Host;
this._client.Port.value = Port;
await this.ConnectAsync(Host, +Port);
}
/** 連線(目前沒有重連機制) */
public async ConnectAsync(host: string, port: number): Promise<void> {
let self = this;
var url: string = "https://api.ipify.org/?format=json";
var xhr: XMLHttpRequest = new XMLHttpRequest();
let ip: string = "";
xhr.onreadystatechange = function (): void {
if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 400)) {
ip = JSON.parse(xhr.responseText)["ip"];
}
};
xhr.open("GET", url, true);
xhr.send();
console.log("[事件]準備連線...");
while (ip === "") {
await Tools.Sleep(1);
}
let checkHttp: string = "";
let ws: string = "";
let index: number = host.indexOf("https://");
if (index != -1) {
checkHttp = "https";
host = host.replace("https://", "");
} else {
checkHttp = window.location.href.substring(0, 5);
host = host.replace("http://", "");
}
if (true) {
console.log("[事件]checkHttp=", checkHttp, host, port);
}
if (checkHttp != "https") {
ws = `ws://${host}:${port}/?ip=${ip}`;
}
else {
ws = `wss://${host}:${port}/?ip=${ip}`;
}
let socket = new WebSocket(ws);
socket.onopen = function (e) {
console.log(`[事件] [${self._client.Name.value}] 連線狀態: true`);
self._client.IsConnect.value = "true";
};
socket.onmessage = function (event) {
// alert(`[message] Data received from server: ${event.data}`);
};
socket.onclose = function (event) {
// if (event.wasClean) {
// // alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
// } else {
// // 例如服务器进程被杀死或网络中断
// // 在这种情况下event.code 通常为 1006
// // alert('[close] Connection died');
// }
};
socket.onerror = function (error) {
// alert(`[error] ${error["message"]}`);
self._client.IsConnect.value = "無回應";
};
}
//#endregion
}

View File

@ -0,0 +1,237 @@
export module BusinessEnum {
export enum BusinessType {
Type1 = "H5",
Type2 = "App"
}
export enum ServerType {
/** WEB格式 */
Web = 1,
/** 外版 */
Out = 2,
/** 送審環境 */
Submit = 3,
/** 內版商業DEMO測試(B2B) */
Internal_release = 4,
/** 內版開發(內網&4G) */
Internal_Dev = 5,
/** 外部商業DEMO(B2B) */
Out_B2B = 6
}
export enum LogoType {
/** 完美(目前只有WEB) */
WM = 1
}
}
/**
@explain .GIT並設定新測試環境
@explain
*/
export default class BusinessTypeSetting {
/** 產品商業類別字串(組合判斷用) */
public static readonly TYPE_BUSINESS: string = "App";
/** 編譯版本 */
public static readonly COMPILE_VERSION: string = "1.3.1";
/** 編譯程式碼版號 */
public static readonly SCRIPT_BUNLE_LIST: string[] = [
"FormTableScript", "CommonScript", "ElementUIScript", "LoginScript", "LobbyScript", "SlotScript"
];
public static readonly ART_UI_BUNLE_LIST: string[] = [
"Common", "CommonSound", "Login", "Lobby", "GameCommon",
"Game_BottomUI_SD", "Game_BigWinJackpot", "GameMessage", "CommonLanguageTexture", "MainControl",
"BindAccount", "SettingPanel", "Shop", "Vip", "Ad",
"Mail", "Chat", "PlayerInfo", "Rank", "Gift",
"ResourceItem", "Backpack", "GettingPanel", "Activity", "Game_BottomUI_BJ"
];
public static readonly DEV_ART_UI_BUNLE_LIST: string[] = [
]
public static readonly ART_GAME_BUNLE_LIST: string[] = [
"Game_1201", "Game_1202", "Game_1302"
]
public static readonly ART_REMOTE_GAME_BUNLE_LIST: string[] = [
"Game_1", "Game_2", "Game_5", "Game_8", "Game_9",
"Game_10", "Game_12", "Game_15", "Game_16", "Game_18",
"Game_23", "Game_24", "Game_25", "Game_26", "Game_27",
"Game_28", "Game_29", "Game_30", "Game_32", "Game_33",
"Game_34", "Game_35", "Game_37", "Game_36", "Game_40",
"Game_44", "Game_48", "Game_50", "Game_51", "Game_58",
"Game_1101", "Game_1401", "Game_1501", "Game_2001", "Game_2003",
"Game_3002", "Game_3003", "Game_3012",
]
/** 送審旗標(讀取外版自動判斷是否送審) */
public static IsSubmit: boolean = false;
/** 跑送審2的手動旗標(若是送審且設為true跑2號環境) */
public static IsSubmitTestFlight: boolean = false;
/** B2B手動旗標(true寫死B2B環境) */
public static IsB2B: boolean = false;
/** 商業LOGO圖代碼(讀同一張表但UI有改的設定) */
public static Logo: number = null!;
/** 連線IP(網頁版會接網址參數所以要多開變數直接指定) */
public static UseHost: string = null!;
/** 連接阜(網頁版會接網址參數所以要多開變數直接指定) */
public static UsePort: number = null!;
/** 資源伺服器網址 */
public static UsePatch: string = null!;
/** 帳號 */
public static Account: string = null!;
/** 密碼 */
public static Password: string = null!;
// =======================================================================================
/** 執行環境ProductEnum.ServerType */
public static UseServerTpye: BusinessEnum.ServerType = BusinessEnum.ServerType.Web;
/** 網頁是否在伺服器上 */
public static readonly CheckOnServer: boolean =
window.location.href.indexOf("localhost") == -1
&& window.location.href.indexOf("/build/") == -1;
/** 網頁測試讀取對應資源的位置 */
public static readonly FolderUrlImg: string = "shared/img/";
public static readonly FolderUrlBg: string = "shared/bg/";
public static readonly FolderUrlJson: string = "shared/jsons/";
public static readonly FolderUrlTxt: string = "shared/txt/";
public static readonly FolderUrlLoading: string = "shared/loading/";
public static readonly FolderUrlMp3: string = "shared/";
public static readonly FolderUrlBundle: string = `Bundle_${true ? "Debug" : "Release"}/`;
public static readonly FolderOS: string = "Android/";
/**遠端Bundle路徑為: URL + BundleName.非遊戲資源到各自平台資料夾找BUNDLE */
public static GetRemoteFileUrl(bundleName: string): string {
let gameNumber: string = bundleName.split("Game_")[1];
var regExp: RegExp = /^[0-9]+$/;
let isGame: boolean = regExp.test(gameNumber);
let bundleUrl: string = `${BusinessTypeSetting.UsePatch}${BusinessTypeSetting.FolderUrlBundle}`;
if (isGame) {
bundleUrl = `${bundleUrl}${bundleName}`;
} else {
bundleUrl = `${bundleUrl}${BusinessTypeSetting.FolderOS}${bundleName}`;
}
return bundleUrl;
}
/**
* PACH資原路徑
* @param type ()
* @returns
*/
public static GetPatchUrl(type: BusinessEnum.ServerType): string {
if (this.UseServerTpye == BusinessEnum.ServerType.Web) {
// TYP2網頁版資源路路徑判斷
if (this.CheckOnServer) {
return "../shared/";
} else {
return "http://patch-dev.online-bj.com//shared/";
}
}
switch (type) {
case BusinessEnum.ServerType.Out:
return "https://patch.online-bj.com/game/";
case BusinessEnum.ServerType.Submit:
if (!this.IsSubmitTestFlight) {
return "https://patch-submit.online-bj.com/game/";
} else {
return "https://patch-submit2.online-bj.com/game/";
}
case BusinessEnum.ServerType.Out_B2B:
return "https://patch-demo.online-bj.com/game/";
case BusinessEnum.ServerType.Internal_release:
return "http://patch-release.online-bj.com/";
case BusinessEnum.ServerType.Internal_Dev:
return "http://patch-dev.online-bj.com/";
default:
console.warn("GetPatchUrl Uncheck ServerType.");
return "http://patch-dev.online-bj.com/";
}
}
/**
* IP
* @param type
* @returns
*/
public static GetHostUrl(type: BusinessEnum.ServerType): string {
if (this.UseServerTpye == BusinessEnum.ServerType.Web) {
return "app.casino.catan.com.tw";
}
switch (type) {
case BusinessEnum.ServerType.Out:
return "https://game.online-bj.com";
case BusinessEnum.ServerType.Submit:
if (!this.IsSubmitTestFlight) {
return "https://submit.online-bj.com";
} else {
return "https://submit2.online-bj.com";
}
case BusinessEnum.ServerType.Out_B2B:
return "https://demo.online-bj.com";
case BusinessEnum.ServerType.Internal_release:
return "https://demo.online-bj.com";
case BusinessEnum.ServerType.Internal_Dev:
return "http://220.134.195.1";
default:
console.warn("GetHostUrl Uncheck ServerType.");
// 只有內網可憐IP
return "app.casino.catan.com.tw";
}
}
/**
*
* @param type
* @returns
*/
public static GetPortNum(type: BusinessEnum.ServerType): number {
if (this.UseServerTpye == BusinessEnum.ServerType.Web) {
// 網頁版測試專用.正式接網頁參數
return 9005;
}
switch (type) {
case BusinessEnum.ServerType.Out:
return 9005;
case BusinessEnum.ServerType.Submit:
if (!this.IsSubmitTestFlight) {
return 9005;
} else {
return 9005;
}
case BusinessEnum.ServerType.Out_B2B:
return 9005;
case BusinessEnum.ServerType.Internal_release:
return 9005;
case BusinessEnum.ServerType.Internal_Dev:
return 19005;
default:
console.warn("GePortNum Uncheck ServerType.");
return 9005;
}
}
public static GetDownloadUrl(type: BusinessEnum.ServerType): string {
switch (type) {
case BusinessEnum.ServerType.Internal_Dev:
return "http://static-dev.online-bj.com/";
default:
let url: string = this.GetHostUrl(type);
url = url.replace("http://", "");
url = url.replace("https://", "");
return "https://static-" + url;
}
}
public static GetUploadUrl(type: BusinessEnum.ServerType): string {
let port: string = ":9080";
switch (type) {
case BusinessEnum.ServerType.Internal_Dev:
return "http://static-dev.online-bj.com" + port;
default:
return this.GetHostUrl(type) + port;
}
}
// =======================================================================================
}

View File

@ -0,0 +1,8 @@
/** 訊息框相關 */
export default class CSMessage {
/** 網路錯誤訊息 */
public static NetError(method: string, state: number, str: string = ""): void {
let error: string = String.Format("[{0}] state:{1} {2}", method, state, str);
console.warn("網路錯誤訊息: ", error);
}
}

22
src/script/Base/Config.ts Normal file
View File

@ -0,0 +1,22 @@
/**放跟ProductSetting沒關係的變數 */
export default class Config {
/**是否是連線模式 */
public static IsOnlineMode: boolean = false;
/**內版帳號登入(目前只支援TYPE1.請從GM工具創好帳號在去DEMO場景加按鈕) */
public static IsDemoLogin: boolean = false;
/**遊戲模式(0一般 1特色.WEB才有分) */
public static GameMode: number = 0;
/**顯示金錢變動LOG */
public static ShowMoneyLog: boolean = true;
/**顯示測試畫面 */
public static ShowTest: boolean = false;
public static GetRunDevice(): number {
return 0;
}
public static IsANDROID(): boolean {
return false;
}
public static IsIOS(): boolean {
return false;
}
}

View File

@ -0,0 +1,237 @@
import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest";
import BusinessTypeSetting from "../BusinessTypeSetting";
import Config from "../Config";
// =======================================================================================
/** 通用回傳SERVER創的帳號 */
interface CommonAccountResponse {
a: string;
pw: string;
}
// =======================================================================================
interface CreateResquest {
p: number;
}
/** 直接玩(訪客給SERVER創帳號) */
export class AccountCreateRequest extends NetRequest<CreateResquest, CommonAccountResponse> {
get Method(): string {
return "account.create";
}
constructor() {
super();
this.Data = {
p: Config.GetRunDevice(),
};
}
}
// =======================================================================================
interface LoginResquest {
p: number;
device_info: string[];
fcm_token: string;
a: string;
pw: string;
ver: string;
}
interface LoginResponse {
pr: string;
cu: string;
}
/** 通用登入 */
export class AccountLoginRequest extends NetRequest<LoginResquest, LoginResponse> {
get Method(): string {
return "account.login";
}
constructor(account: string, password: string) {
super();
this.Data = {
p: Config.GetRunDevice(),
device_info: ["Windows", "Windows"],
fcm_token: "",
a: account,
pw: password,
ver: BusinessTypeSetting.COMPILE_VERSION
};
}
}
// =======================================================================================
interface CustomResquest {
a: string;
pw: string;
}
/** 自定帳號榜定 */
export class CustomBindRequest extends NetRequest<CustomResquest, null> {
get Method(): string {
return "register.account_bind";
}
constructor(account: string, password: string) {
super();
this.Data = {
a: account,
pw: password,
};
}
}
/** 自定帳號登入(回傳SERVER帳號) */
export class CustomLoginRequest extends NetRequest<CustomResquest, CommonAccountResponse> {
get Method(): string {
return "register.account_login";
}
constructor(account: string, password: string) {
super();
this.Data = {
a: account,
pw: password,
};
}
}
// =======================================================================================
interface FBResquest {
t: string;
}
/** FB綁定 */
export class FBBindRequest extends NetRequest<FBResquest, null> {
get Method(): string {
return "register.fb_bind";
}
constructor(token: string) {
super();
this.Data = {
t: token,
};
}
}
/** FB登入(回傳SERVER帳號) */
export class FBLoginRequest extends NetRequest<FBResquest, CommonAccountResponse> {
get Method(): string {
return "register.fb_login";
}
constructor(token: string) {
super();
this.Data = {
t: token,
};
}
}
// =======================================================================================
interface GoogleResquest {
c: string;
}
/** GOOGLE綁定 */
export class GoogleBindRequest extends NetRequest<GoogleResquest, null> {
get Method(): string {
return "register.google_bind";
}
constructor(token: string) {
super();
this.Data = {
c: token,
};
}
}
/** GOOGLE登入(回傳SERVER帳號) */
export class GoogleLoginRequest extends NetRequest<GoogleResquest, CommonAccountResponse> {
get Method(): string {
return "register.google_login";
}
constructor(token: string) {
super();
this.Data = {
c: token,
};
}
}
// =======================================================================================
interface AppleResquest {
c: string;
}
/** APPEL綁定 */
export class AppleBindRequest extends NetRequest<AppleResquest, null> {
get Method(): string {
return "register.apple_bind";
}
constructor(token: string) {
super();
this.Data = {
c: token,
};
}
}
/** APPLE登入(回傳SERVER帳號) */
export class AppleLoginRequest extends NetRequest<AppleResquest, CommonAccountResponse> {
get Method(): string {
return "register.apple_login";
}
constructor(token: string) {
super();
this.Data = {
c: token,
};
}
}
// =======================================================================================
/** 電話驗證 */
export interface PhoneCodeRequest {
p: string;
}
export class PhoneGet extends NetRequest<PhoneCodeRequest, string> {
get Method(): string {
return "register.phone_code";
}
constructor(p: string) {
super();
this.Data = {
p: p
};
}
}
export interface PhoneBindRequest {
c: string;
}
export class PhoneBind extends NetRequest<PhoneBindRequest, string> {
get Method(): string {
return "register.phone_bind";
}
constructor(c: string) {
super();
this.Data = {
c: c
};
}
}
// =======================================================================================
/** 旗標更新 */
export class FlagOpenAdd extends NetRequest<number, string> {
get Method(): string {
return "flag.open_add";
}
constructor(type: number) {
super();
this.Data = type;
}
}
// ========================================================================================
export interface ForgotInfo {
a: string;
p: string;
}
/** 忘記密碼 */
export class ForgotPassword extends NetRequest<ForgotInfo, null> {
get Method(): string {
return "register.account_forget";
}
constructor(account: string, phone: string) {
super();
this.Data = {
a: account,
p: phone,
};
}
}

View File

@ -0,0 +1,72 @@
import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest";
export interface RankInfo {
t: number;
p?: number;
id?: number;
}
export class AppRankInfo extends NetRequest<RankInfo, JSON> {
get Method(): string {
return "rank.info";
}
constructor(Type: number, Parameter?: number) {
super();
this.Data = {
t: Type,
p: Parameter,
};
}
}
export class AppRankHistory extends NetRequest<RankInfo, JSON> {
get Method(): string {
return "rank.history";
}
constructor(Type: number, Parameter: number, DayId: number) {
super();
this.Data = {
id: DayId,
t: Type,
p: Parameter
};
}
}
export interface RankReplayInfo {
id: number;
t: number;
r: number;
p: number;
}
export class AppRankLog extends NetRequest<RankReplayInfo, JSON> {
get Method(): string {
return "rank.log";
}
constructor(DayId: number, Type: number, rank: number, Parameter: number) {
super();
this.Data = {
id: DayId,
t: Type,
r: rank,
p: Parameter
};
}
}
export class TestAppRankLog extends NetRequest<RankReplayInfo, JSON> {
get Method(): string {
return "rank.log_test";
}
constructor(DayId: number, Type: number, rank: number, Parameter: number) {
super();
this.Data = {
id: DayId,
t: Type,
r: rank,
p: Parameter
};
}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "a69fe64f-177f-4e4b-83f0-1f418203d85f",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "f9edb32f-c4ab-4e5d-8270-71fa609e1db7",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,20 @@
declare global {
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;
});
}
export { };

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "0c3d1ca6-bdaf-4a00-b209-6ef460802cdc",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "01b35dee-e6e0-4a6e-a73c-3b49c37f1c5f",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,125 @@
/**
* 回呼函數: fnname (arg: TArg): void
*/
interface ActionCallback<TArg> {
(arg: TArg): void;
}
interface Struct<TArg> {
callback: ActionCallback<TArg>;
target: any;
once?: boolean;
}
export class Action<TArg> {
private _queue: Struct<TArg>[] = [];
/**
*
* @param callback 回呼函數: fnname (arg: TArg): void
* @param bindTarget this綁定的對象
*/
AddCallback(callback: ActionCallback<TArg>, bindTarget?: any) {
let q = <Struct<TArg>> {
callback: callback,
target: bindTarget
};
this._queue.push(q);
}
/**
* ()
* @param callback 回呼函數: fnname (arg: TArg): void
* @param bindTarget this綁定的對象
*/
AddCallbackOnce(callback: ActionCallback<TArg>, bindTarget?: any) {
let q = <Struct<TArg>> {
callback: callback,
target: bindTarget,
once: true
};
this._queue.push(q);
}
/**
*
* @param callback
*/
RemoveByCallback(callback: ActionCallback<TArg>) {
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);
}
}
}
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "ea9bf762-40a7-4bab-b949-8d5b3d4289e2",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,85 @@
import { Action } from "./Action";
import { ActionWithType } from "./ActionWithType";
import { ActionWithType2 } from "./ActionWithType2";
const { ccclass, property } = console._decorator;
enum CustomType {
Ex1, Ex2
}
class CustomEvent extends ActionWithType<CustomType, number> { }
class CustomEvent2 extends ActionWithType2<CustomType, number> { }
@ccclass
export default class NewClass extends console.Component {
callback: Action<number> = new Action<number>();
customCallback: CustomEvent = new CustomEvent();
customCallback2: CustomEvent2 = new CustomEvent2();
private num: number = 0;
start() {
this.callback.AddCallback(this.CB, this);
this.callback.AddCallbackOnce(this.OnceCB, this);
this.customCallback.AddCallback(CustomType.Ex1, this.CBType, this);
this.customCallback.AddCallbackOnce(CustomType.Ex2, this.OnceCBType, this);
this.customCallback2.AddCallback(CustomType.Ex2, this.CBTypeAllin1, this);
this.customCallback2.AddCallbackOnce(CustomType.Ex1, this.CBTypeAllin1, this);
}
DispatchClick() {
this.num++;
this.callback.DispatchCallback(this.num);
this.customCallback.DispatchCallback(CustomType.Ex1, this.num);
this.customCallback.DispatchCallback(CustomType.Ex2, this.num);
this.customCallback2.DispatchCallback(CustomType.Ex1, this.num);
this.customCallback2.DispatchCallback(CustomType.Ex2, this.num);
}
RemoveEventClick() {
this.callback.RemoveByCallback(this.CB);
// this.callback.RemoveByCallback(this.OnceCB);
// this.callback.RemoveByBindTarget(this);
// this.callback.RemoveAll();
// this.callbackWithType.RemoveByCallback(this.CBType);
// this.callbackWithType.RemoveByCallback(this.OnceCBType);
this.customCallback.RemoveByType(CustomType.Ex1);
// this.callbackWithType.RemoveByType(CustomType.Ex2);
// this.callbackWithType.RemoveByBindTarget(this);
// this.callbackWithType.RemoveAll();
}
OnceCB(x: number) {
console.log(`OnceCB [${this.num}]`);
}
CB(x: number) {
console.log(`CB [${this.num}]`);
}
OnceCBType(x: number) {
console.log(`OnceCBType [${this.num}]`);
}
CBType(x: number) {
console.log(`CBType [${this.num}]`);
}
CBTypeAllin1(type: CustomType, x: number) {
// switch (type) {
// case CustomType.Ex1:
// break;
// case CustomType.Ex2:
// break;
// }
console.log(`CBTypeAllin1 [${CustomType[type]}][${this.num}]`);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "cc645b73-6192-414d-a5bc-4220c24e322d",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,166 @@
/**
* 回呼函數: fnname (arg: TArg): void
*/
interface ActionCallback<TArg> {
(arg: TArg): void;
}
interface Struct<TType, TArg> {
callback: ActionCallback<TArg>;
target: any;
type: TType;
once?: boolean;
}
export class ActionWithType<TType, TArg> {
private _queue: Struct<TType, TArg>[] = [];
/**
*
* @param callback 回呼函數: fnname (arg: TArg): void
* @param bindTarget this綁定的對象
*/
AddCallback(type: TType, callback: ActionCallback<TArg>, bindTarget?: any) {
let q = <Struct<TType, TArg>> {
callback: callback,
target: bindTarget,
type: type
};
this._queue.push(q);
}
/**
* ()
* @param callback 回呼函數: fnname (arg: TArg): void
* @param bindTarget this綁定的對象
*/
AddCallbackOnce(type: TType, callback: ActionCallback<TArg>, bindTarget?: any) {
let q = <Struct<TType, TArg>> {
callback: callback,
target: bindTarget,
type: type,
once: true
};
this._queue.push(q);
}
/**
*
* @param callback
*/
RemoveByCallback(callback: ActionCallback<TArg>) {
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<TArg>) {
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);
}
}
}
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "61d770ec-24e2-425b-b66b-2b03e192e45b",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,166 @@
/**
* 回呼函數: fnname (type: TType, arg: TArg): void
*/
interface ActionCallback<TType, TArg> {
(type: TType, arg: TArg): void;
}
interface Struct<TType, TArg> {
callback: ActionCallback<TType, TArg>;
target: any;
type: TType;
once?: boolean;
}
export class ActionWithType2<TType, TArg> {
private _queue: Struct<TType, TArg>[] = [];
/**
*
* @param callback 回呼函數: fnname (type: TType, arg: TArg): void
* @param bindTarget this綁定的對象
*/
AddCallback(type: TType, callback: ActionCallback<TType, TArg>, bindTarget?: any) {
let q = <Struct<TType, TArg>> {
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<TType, TArg>, bindTarget?: any) {
let q = <Struct<TType, TArg>> {
callback: callback,
target: bindTarget,
type: type,
once: true
};
this._queue.push(q);
}
/**
*
* @param callback
*/
RemoveByCallback(callback: ActionCallback<TType, TArg>) {
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<TType, TArg>) {
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);
}
}
}
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "ed703ebd-efd4-4ec9-9b84-de748ef8f9e8",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "09d69d12-a6d1-4bb1-bcfe-faa811632467",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,68 @@
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) {
let str = "";
let i = 0, len = array.length;
while(i < len) {
let c = array[i++];
switch (c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
str += String.fromCharCode(c);
break;
case 12: case 13:
str += String.fromCharCode(((c & 0x1F) << 6) | (array[i++] & 0x3F));
break;
case 14:
str += String.fromCharCode(((c & 0x0F) << 12) | ((array[i++] & 0x3F) << 6) | ((array[i++] & 0x3F) << 0));
break;
}
}
return str;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "43bf5724-e939-4189-b981-c32ef694e5a5",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "9f510f2b-83d8-4097-8683-32d6134323fb",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "9a414131-91a8-4d02-9921-9d1ee01764c3",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "fbfe97a8-24ca-4f67-b049-323652c7194b",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -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<any> {
if (this._action) {
this._action();
}
return { done: true, value: undefined };
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "3cf9e5c3-520f-48a9-8821-9be76d519765",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,87 @@
import { IEnumeratorV2, IEnumeratorV2Started } from "../IEnumeratorV2";
import { CoroutineExecutor } from "./CoroutineExecutor";
export abstract class BaseEnumerator implements IEnumeratorV2 {
public nextEnumerator: BaseEnumerator;
abstract next(value?: any): IteratorResult<any>;
Start(target?: any): IEnumeratorV2Started {
let executor = LazyLoad.EnumeratorExecutor(this, target);
CoroutineExecutor.instance.StartCoroutine(executor);
return executor;
}
Then(iterator: Iterator<any>): 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<any>[]): 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<any>[]): 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) {
return new (require("./EnumeratorExecutor") as typeof import("./EnumeratorExecutor")).EnumeratorExecutor(enumerator, target);
}
export function SingleEnumerator(iterator: Iterator<any>) {
return new (require("./SingleEnumerator") as typeof import("./SingleEnumerator")).SingleEnumerator(iterator);
}
export function ParallelEnumerator(...iterators: Iterator<any>[]) {
return new (require("./ParallelEnumerator") as typeof import("./ParallelEnumerator")).ParallelEnumerator(iterators);
}
export function WaitTimeEnumerator(seconds: number) {
return new (require("./WaitTimeEnumerator") as typeof import("./WaitTimeEnumerator")).WaitTimeEnumerator(seconds);
}
export function ActionEnumerator(action: Function) {
return new (require("./ActionEnumerator") as typeof import("./ActionEnumerator")).ActionEnumerator(action);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "4084537c-c7e8-4d47-b283-39be77ef9685",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,94 @@
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: console.Scheduler;
constructor() {
this._scheduler = console.director.getScheduler();
this._scheduler.enableForTarget(this);
this._scheduler.scheduleUpdate(this, 0, true);
}
StartCoroutine(executor: EnumeratorExecutor) {
executor.next(0);
//TODO: 這邊要考量next後馬上接BaseEnumerator/Iterator的情形
if (!this._isRunning) {
this._executors.push(executor);
if (this._scheduler.isTargetPaused(this)) {
this._scheduler.resumeTarget(this);
}
} 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) {
if (this._nextExecutors.length) {
this._executors.push(...this._nextExecutors);
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);
}
}
this._cleanRemoved = false;
}
if (this._executors.length == 0) {
if (true) {
console.log("[CoroutineV2] All coroutines done");
}
this._scheduler.pauseTarget(this);
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;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "f25b1e42-90d8-4fc0-9925-6e7e92296d57",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,168 @@
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<any> {
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<any>;
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(<Iterator<any>>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(<Iterator<any>>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;
(<Promise<any>>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) {
console.error(e.stack);
} else {
console.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) {
console.error(e.stack);
} else {
console.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();
}
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "91cb70ed-e6f9-4ce0-b7c5-1720087b3bd7",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -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<any>[]) {
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<any> {
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 };
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "017ebc9a-5152-4f94-bbaf-e3b914e87b41",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,18 @@
import { BaseEnumerator } from "./BaseEnumerator";
export class SingleEnumerator extends BaseEnumerator {
private _iterator: Iterator<any>;
constructor(iterator: Iterator<any>) {
super();
this._iterator = iterator;
}
next(value?: any): IteratorResult<any> {
if (!this._iterator) {
return { done: true, value: undefined };
}
return this._iterator.next(value);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "c439d019-2da8-48b8-a65b-bff928d0fda8",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -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<any> {
let delta = value as number;
this._seconds -= delta;
if (this._seconds <= 0) {
return { done: true, value: 0 };
} else {
return { done: false, value: this._seconds };
}
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "a3038e6f-1bb4-4aff-a686-b69209df3592",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,197 @@
import { CoroutineV2 } from "./CoroutineV2";
import { IEnumeratorV2Started } from "./IEnumeratorV2";
const { ccclass, property } = console._decorator;
class A {
private numbers: number[] = [1, 2];
private index = 0;
[Symbol.iterator](): IterableIterator<any> {
return this;
}
next(value?: any): IteratorResult<any> {
if (this.index < this.numbers.length) {
let value = this.numbers[this.index++];
console.log(`A=> ${value}`);
return {
done: false,
value: value
};
}
return { done: true, value: undefined };
}
}
@ccclass
export default class CoroutineExample extends console.Component {
private _routine: IEnumeratorV2Started;
private _obj: Object = { "a": true };
private _obj2: Object = { "b": true };
private _num: number = 3;
button1Clicked() {
// this._routine = CoroutineV2
// .Parallel(this.Coroutine1(1, 3), this.Coroutine1(4, 6))
// .ThenWaitTime(2)
// .Then(this.Coroutine1(7, 9))
// .ThenWaitTime(2)
// .ThenAction(() => console.log("action callback 1"))
// .ThenWaitTime(2)
// .ThenAction(this.actionCallback)
// //.Start(this);
// .Start(this);
// this._routine = CoroutineV2.Single(this.FunA()).Start(this);
this._routine = CoroutineV2.Single(this.Test1_1()).Start(this);
// this._routine = CoroutineV2.Single(this.Test2_1()).Start(this);
}
*Test1_1() {
yield null;
yield* this.Test1_2();
// CoroutineV2.Single(this.Test1_3()).Start(this);
yield this.Test1_3();
}
*Test1_2() {
yield null;
}
*Test1_3() {
yield this.Test1_3_1();
yield CoroutineV2.Single(this.Test1_4()).Start(this._obj);
// yield CoroutineV2.Single(this.Test1_4()); //.Start(this);
// yield *this.Test1_4();
console.log("main wait 3");
yield CoroutineV2.WaitTime(2);
console.log("done");
}
*Test1_3_1() {
yield this.Test1_3_2();
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_1.1");
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_1.2");
}
*Test1_3_2() {
yield this.Test1_3_3();
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_2.1");
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_2.2");
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_2.3");
}
*Test1_3_3() {
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_3.1");
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_3.2");
yield CoroutineV2.WaitTime(1);
console.log("Test1_3_3.3");
}
*Test1_4() {
this._num++;
console.log(`WaitTime2 ${this._num}`);
yield CoroutineV2.WaitTime(2).Start(this._obj2);
this._num++;
console.log(`WaitTime2 ${this._num}`);
yield CoroutineV2.WaitTime(2).Start(this._obj2);
this._num++;
console.log(`WaitTime2 ${this._num}`);
}
*Test2_1() {
console.log("111");
CoroutineV2.Single(this.Test2_2()).Start(this);
console.log("333");
}
*Test2_2() {
console.log("222");
return;
}
button2Clicked() {
// this._routine && this._routine.Stop();
if (this._obj2) {
CoroutineV2.StopCoroutinesBy(this._obj2);
this._obj2 = null;
return;
}
if (this._obj) {
CoroutineV2.StopCoroutinesBy(this._obj);
this._obj = null;
return;
}
CoroutineV2.StopCoroutinesBy(this);
}
button3Clicked() {
// CoroutineV2.StopCoroutinesBy(this);
this._routine && this._routine.Pause();
}
button4Clicked() {
// CoroutineV2.StopCoroutinesBy(this);
this._routine && this._routine.Resume();
}
*Coroutine1(start: number, end: number) {
for (let i = start; i <= end; i++) {
// yield CoroutineV2.WaitTime(1).Start(); // Start()可以省略, 會由外層啟動
// yield CoroutineV2.WaitTime(1).Start(this); // target也可以省略, 由外層的target控制
yield CoroutineV2.WaitTime(1).Start();
console.log(`C1 => ${i}`);
// 嵌套
yield CoroutineV2
.WaitTime(1)
.ThenParallel(
// 再嵌套
CoroutineV2.Action(() => console.log("start parallel")),
this.Coroutine2(10, 2),
this.Coroutine2(20, 2),
new A())
.ThenAction(() => console.log("end parallel"))
.Start();
// Promise
yield this.loadItemAsync("settings.json");
}
}
*Coroutine2(num: number, repeat: number) {
for (let i = 0; i < repeat; i++) {
//yield CoroutineV2.WaitTime(2);
yield 0;
console.log(`C2: ${num}`);
// yield CoroutineV2.WaitTime(1);
}
}
actionCallback() {
console.log("action callback 2");
}
loadItemAsync(id: string): Promise<{ id: string }> {
return new Promise((resolve) => {
console.log('loading item start:', id);
setTimeout(() => {
resolve({ id: id });
console.log('loading item done:', id);
}, 3000);
});
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "dfd32c11-76f6-4e38-9272-1d7966d1ef3c",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -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<any>, 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<any>): IEnumeratorV2 {
if (iterator instanceof BaseEnumerator) {
return iterator;
} else {
return new SingleEnumerator(iterator);
}
}
/**
*
*/
export function Parallel(...iterators: Iterator<any>[]): IEnumeratorV2 {
return new ParallelEnumerator(iterators);
}
/**
*
*/
export function Serial(...iterators: Iterator<any>[]): 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);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "fc38e505-bd37-44c3-9e0a-fd463bb88c51",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,16 @@
export interface IEnumeratorV2 extends Iterator<any> {
Start(target?: any): IEnumeratorV2Started;
Then(iterator: Iterator<any>): IEnumeratorV2;
ThenSerial(...iterators: Iterator<any>[]): IEnumeratorV2;
ThenParallel(...iterators: Iterator<any>[]): IEnumeratorV2;
ThenAction(action: Function, delaySeconds?: number): IEnumeratorV2;
ThenWaitTime(seconds: number): IEnumeratorV2;
}
export interface IEnumeratorV2Started {
readonly Current: any;
Pause(): void;
Resume(): void;
Stop(): void;
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "df3ab07d-3d2b-4552-b454-29b95223ea85",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "6f870efd-e869-4415-9cf2-138ab667cd5d",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "5e6c027f-ce4b-47fa-968c-f3bb6059ad81",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,13 @@
import { Action } from "../../CSharp/System/Action";
import { INetRequest } from "./INetRequest";
import { INetResponse } from "./INetResponse";
export interface INetConnector {
readonly OnDataReceived: Action<INetResponse<any>>;
readonly OnDisconnected: Action<void>;
readonly IsConnected: boolean;
SendAsync<TRequest, TResponse>(req: INetRequest<TRequest, TResponse>): Iterator<any>;
Send<TRequest, TResponse>(req: INetRequest<TRequest, TResponse>);
Logout();
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "f97991b5-0da6-4220-ab29-13c8f8f7e405",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
import { INetResponse } from "./INetResponse";
export interface INetRequest<TRequest, TResponse> {
readonly Method: string;
readonly MethodBack: string;
Data: TRequest;
Result: INetResponse<TResponse>;
SendAsync(): Promise<Iterator<any>>;
Send();
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "339fcf27-bdb9-4b8f-ae18-dd54c9500145",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,6 @@
export interface INetResponse<TResponse> {
readonly Method: string;
readonly Status: number;
readonly Data: TResponse;
readonly IsValid: boolean;
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "c4cb0cd4-b98c-4f8e-b1e6-ac3b51281b28",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "94e55972-723c-4dab-9ebc-870bd5043fca",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,69 @@
import { CoroutineV2 } from "../../CoroutineV2/CoroutineV2";
import { INetResponse } from "../Core/INetResponse";
import { NetConnector } from "../NetConnector";
import { NetManager } from "../NetManager";
import { Slot1_SpinRequestExample } from "./Slot1_SpinRequestExample";
const { ccclass, property } = console._decorator;
@ccclass
export default class NetTester extends console.Component {
onConnectClicked() {
CoroutineV2.StartCoroutine(this.ConnectAsync());
}
*ConnectAsync() {
if (!NetManager.HasInit) {
let conn = new NetConnector("192.168.7.165", 9005);
conn.OnDataReceived.AddCallback(this.OnNetDataReceived, this);
conn.OnDisconnected.AddCallback(this.OnNetDisconnected, this);
conn.OnLoadUIMask.AddCallback(this.OnLoadUIMask, this);
NetManager.Initialize(conn);
}
console.log("連線中...");
yield NetManager.ConnectAsync(); // 同個connector要再次連線, 可以不用叫CasinoNetManager.Initialize(), 但要先叫CasinoNetManager.Disconnect()
console.log(`連線狀態: ${NetManager.IsConnected}`);
}
onDisconnectClicked() {
console.log("中斷連線中...");
NetManager.Disconnect(); // 中斷連線
}
onSendMessageClicked1() {
console.log("發送訊息(不使用協程)");
let req = new Slot1_SpinRequestExample(401);
req.Send();
// CasinoNetManager.Send(req);
}
onSendMessageClicked2() {
CoroutineV2.StartCoroutine(this.SendAsync());
}
*SendAsync() {
console.log("發送訊息中(使用協程)...");
let req = new Slot1_SpinRequestExample(399);
yield req.SendAsync();
// yield CasinoNetManager.SendAsync(req);
let resp = req.Result;
console.log(`發送協程完畢, Server回應: ${resp.Method}(${JSON.stringify(resp.Data)}), 狀態: ${resp.Status}`);
// console.log(`使用介面資料: ${resp.Data.slot}`);
}
private OnNetDisconnected() {
console.log("[事件] 收到連線中斷事件");
}
private OnNetDataReceived(resp: INetResponse<any>) {
console.log(`[事件] 收到server呼叫: ${resp.Method}(${JSON.stringify(resp.Data)}), 狀態: ${resp.Status}`);
}
private OnLoadUIMask(value: boolean) {
console.log(`[事件] LoadUIMask: ${value}`);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "0cb7df7a-d0e7-4ce1-832e-4583cf3385e5",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,37 @@
import { NetRequest } from "../NetRequest";
// 送給server的結構
interface Request {
pay: number;
}
// server回應的結構
interface Response {
pay: [[number, number]];
/**拉霸結果 */
slot: number[];
get: any[];
}
// class Account_CreateRequest extends CasinoRequest<number, any> { // 也可以是基本類或any, 但不建議用any, 使用介面ts才會有提示
export class Slot1_SpinRequestExample extends NetRequest<Request, Response> {
get Method(): string {
return "slot1.spin";
}
// MethodBack預設回傳Method, 不一樣才需要覆寫
// get MethodBack(): string {
// return "slot1.freespin";
// }
constructor(totalBet: number) {
super();
// 原本的SingleValue拿掉, 統一使用Data來存送出結構
// this.Data = 2;
this.Data = {
pay: totalBet,
};
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "1af9e6af-3dc3-4d02-8b24-481adc07932a",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,4 @@
export default class NetConfig {
/**是否顯示RPC接送JSON的LOG */
public static ShowServerLog: boolean = true;
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "c7f5f6a9-94fd-4f5f-9f0a-545cd14edca9",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,263 @@
import { Tools } from "../../../Tools";
import { BaseEnumerator } from "../CoroutineV2/Core/BaseEnumerator";
import { Action } from "../CSharp/System/Action";
import { Encoding } from "../CSharp/System/Text/Encoding";
import { INetRequest } from "./Core/INetRequest";
import { INetResponse } from "./Core/INetResponse";
import NetConfig from "./NetConfig";
import { NetManager } from "./NetManager";
export class NetConnector {
readonly OnDataReceived: Action<INetResponse<any>> = new Action<INetResponse<any>>();
readonly OnDisconnected: Action<void> = new Action<void>();
readonly OnLoadUIMask: Action<boolean> = new Action<boolean>();
get IsConnected() {
return this._ws && this._ws.readyState === WebSocket.OPEN;
}
private _host: string;
private _ws: WebSocket = null!;
private _waitings: WsRequestEnumerator[] = [];
constructor(host: string, port: number, ip: string) {
let checkHttp: string = "";
let index: number = host.indexOf("https://");
if (index != -1) {
checkHttp = "https";
host = host.replace("https://", "");
} else {
checkHttp = window.location.href.substring(0, 5);
host = host.replace("http://", "");
}
if (true) {
console.log("[事件]checkHttp=", checkHttp, host, port);
}
if (checkHttp != "https") {
this._host = `ws://${host}:${port}/?ip=${ip}`;
}
else {
this._host = `wss://${host}:${port}/?ip=${ip}`;
}
}
async ConnectAsync() {
if (this._ws) {
throw new Error("請先執行CasinoNetManager.Disconnect()中斷連線");
}
this._ws = new WebSocket(this._host);
this._ws.binaryType = 'arraybuffer';
this._ws.onopen = this.OnWebSocketOpen.bind(this);
this._ws.onmessage = this.OnWebSocketMessage.bind(this);
this._ws.onerror = this.OnWebSocketError.bind(this);
this._ws.onclose = this.OnWebSocketClose.bind(this);
while (!NetManager.IsConnected) {
await Tools.Sleep(1);
}
return new WsConnectEnumerator(this._ws);
}
async Send(req: INetRequest<any, any>) {
if (!this.IsConnected) return;
let json = [req.Method];
if (req.Data != null && req.Data != undefined && req.Data) {
json[1] = req.Data;
}
if (true && NetConfig.ShowServerLog) {
if (req.Data != null && req.Data != undefined && req.Data) {
console.log(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`);
} else {
console.log(`[RPC] 傳送server資料: ${req.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);
await this._ws.send(buffer);
}
async SendAsync(req: INetRequest<any, any>, mask: boolean) {
let iterator = new WsRequestEnumerator(req);
if (!this.IsConnected) {
iterator.SetResponse(ErrorResponse);
} else {
this._waitings.push(iterator);
if (mask) {
this.OnLoadUIMask.DispatchCallback(true);
}
this.Send(req);
while (!iterator.Done) {
await Tools.Sleep(1);
}
}
return iterator;
};
Disconnect() {
this.WebSocketEnded();
}
private WebSocketEnded() {
if (!this._ws) return;
this._ws.close();
this._ws.onopen = null;
this._ws.onmessage = null;
this._ws.onclose = () => { };
this._ws = null!;
this.CleanWaitings();
this.OnDisconnected.DispatchCallback();
}
private CleanWaitings() {
for (let w of this._waitings) {
w.SetResponse(ErrorResponse);
this.OnLoadUIMask.DispatchCallback(false);
}
this._waitings.length = 0;
}
private OnWebSocketOpen(e: Event) {
if (true) {
console.log(`[RPC] ${this._host} Connected.`);
}
}
private OnWebSocketMessage(e: MessageEvent) {
if (e.data instanceof ArrayBuffer) {
this.ParseRpcMessage(e.data);
} else if (e.data instanceof Blob) {
let reader = new FileReader();
reader.onload = (e) => { this.ParseRpcMessage(<ArrayBuffer>reader.result); reader.onload = null; }
reader.readAsArrayBuffer(e.data);
} else {
throw new Error(`未知的OnWebSocketMessage(e.data)類型: ${e.data}`);
}
}
private ParseRpcMessage(buffer: ArrayBuffer) {
let startIndex = 0, byteLength = buffer.byteLength;
while (startIndex + 4 < byteLength) {
let strlen = new DataView(buffer, startIndex, 3).getUint16(0, true);
let str = Encoding.UTF8.GetString(new Uint8Array(buffer, startIndex + 4, strlen));
startIndex += strlen + 4;
try {
let json = JSON.parse(str);
let method = <string>json[0];
let status = <number>json[1][0];
let data = json[1][1];
let resp = <INetResponse<any>>{
Method: method,
Status: status,
Data: data,
IsValid: method && status === 0
};
if (true && NetConfig.ShowServerLog) {
if (data) {
console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`);
} else {
console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`);
}
}
let dispatch = true;
for (let i = 0, len = this._waitings.length; i < len; i++) {
let w = this._waitings[i];
if (w.MethodBack === resp.Method) {
dispatch = false;
this._waitings.splice(i, 1);
w.SetResponse(resp);
this.OnLoadUIMask.DispatchCallback(false);
break;
}
}
if (dispatch) {
this.OnDataReceived.DispatchCallback(resp);
}
}
catch
{
throw new Error(`[RPC] 無法解析Server回應: ${str}`);
}
}
}
private OnWebSocketError(ev: Event) {
throw new Error(`[RPC] 無法解析Server回應: ${ev}`);
}
private OnWebSocketClose(e: CloseEvent) {
this.WebSocketEnded();
}
}
const ErrorResponse: INetResponse<any> = {
Status: -1,
Method: "",
Data: {},
IsValid: false,
};
class WsConnectEnumerator extends BaseEnumerator {
private _ws: WebSocket;
constructor(ws: WebSocket) {
super();
this._ws = ws;
}
next(value?: any): IteratorResult<any> {
return {
done: this._ws.readyState === WebSocket.OPEN || this._ws.readyState === WebSocket.CLOSED,
value: undefined
};
}
}
class WsRequestEnumerator extends BaseEnumerator {
readonly MethodBack: string;
private _req: INetRequest<any, any>;
private _done: boolean = false;
public get Done(): boolean { return this._done; }
constructor(req: INetRequest<any, any>) {
super();
this._req = req;
this.MethodBack = req.MethodBack;
}
SetResponse(resp: INetResponse<any>) {
this._req.Result = resp;
this._done = true;
}
next(value?: any): IteratorResult<any> {
return {
done: this._done,
value: undefined
};
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "221e1688-cc40-450d-9248-464978540a85",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,49 @@
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 async ConnectAsync() {
this.CheckConnector();
return await this._connector.ConnectAsync();
}
/**
*
*/
static Disconnect() {
this.CheckConnector();
this._connector.Disconnect();
}
/**
* Server,
* @param req
*/
static Send(req: INetRequest<any, any>) {
this.CheckConnector();
this._connector.Send(req);
}
/**
* Server,
* @param req
*/
static async SendAsync(req: INetRequest<any, any>, mask: boolean) {
this.CheckConnector();
return await this._connector.SendAsync(req, mask);
}
private static CheckConnector() {
if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector");
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "7c3e375d-3672-42e7-8a45-dd5ecf9d5fe8",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,21 @@
import { INetRequest } from "./Core/INetRequest";
import { NetManager } from "./NetManager";
export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> {
abstract get Method(): string;
get MethodBack(): string {
return this.Method;
}
Data: TResquest;
Result: import("./Core/INetResponse").INetResponse<TResponse>;
async SendAsync(mask: boolean = false): Promise<Iterator<any>> {
return await NetManager.SendAsync(this, mask);
}
Send() {
NetManager.Send(this);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "36534597-4273-48e8-bbeb-8dde4857d26f",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
{
"ver": "1.0.8",
"uuid": "90f2152c-2c37-4c7c-b3a3-04c8aee53c34",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "8e05805d-5ab8-4526-8463-f4c837e23534",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,5 @@
{
"ver": "2.0.0",
"uuid": "6ab253ff-8c5d-419f-9f8b-5cf0ef661a28",
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "c87ad2c2-0bf9-4822-84db-00b939f614ee",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.2",
"uuid": "89d65072-29d8-4f58-a9d7-5750406209e6",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

Some files were not shown because too many files have changed in this diff Show More