[add] 進機台
This commit is contained in:
		| @@ -17,7 +17,7 @@ | |||||||
|  |  | ||||||
| <body oncontextmenu="return false"> | <body oncontextmenu="return false"> | ||||||
| 	<noscript>You need to enable JavaScript to run this app.</noscript> | 	<noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
| 	<div id="root"></div> | 	<div id="root" style="height: 100vh;"></div> | ||||||
| 	<script type="module" src="/src/index.tsx"></script> | 	<script type="module" src="/src/index.tsx"></script> | ||||||
| </body> | </body> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,23 +1,9 @@ | |||||||
|  | import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||||
| import { confirmModalObj } from "@/UI/MessageBox/ConfirmModalContext"; | import { gameSync } from "@/utils/setRPCData"; | ||||||
| import { modalObj } from "@/UIControl/ModalContext"; |  | ||||||
| import { Cocos } from "@/assets/VueScript/Cocos"; |  | ||||||
| import { CommonEventCallBack, JackpotPoolCallBack } from "@/assets/VueScript/CocosVueScript"; |  | ||||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; |  | ||||||
| import { chatLog, chatMessage, setChatBanTime } from "@/components/ModalContent/ChatRoomModal/chatUtils"; |  | ||||||
| import Config from "@/define/Config"; |  | ||||||
| import Player from "@/modules/player"; |  | ||||||
| import UserData from "@/modules/player/UserData"; |  | ||||||
| import { State } from "@/modules/player/define/data"; |  | ||||||
| import { ILineShareData, ModalContentType } from "@/types"; |  | ||||||
| import { CommonEventType } from "@/utils"; |  | ||||||
| import { NumberEx } from "@/utils/Number/NumberEx"; |  | ||||||
| import { activityComSync, backpackInfo, friendAllowList, friendDenyList, profileInfo, txnCenter, txnNew, txnTrade, txnUserAdd, vipInfo } from "@/utils/setRPCData"; |  | ||||||
| import MainControl from "../MainControl/MainControl"; | import MainControl from "../MainControl/MainControl"; | ||||||
| import CSMessage from "../Message/CSMessage"; | import CSMessage from "../Message/CSMessage"; | ||||||
| import CSResource from "../ResourceItem/CSResource"; |  | ||||||
| import IResourceItem from "../ResourceItem/IResourceItem"; |  | ||||||
|  |  | ||||||
| export default class MainControlData { | export default class MainControlData { | ||||||
|  |  | ||||||
| @@ -46,7 +32,7 @@ export default class MainControlData { | |||||||
| 	private _disconnectErrorType: number = null; | 	private _disconnectErrorType: number = null; | ||||||
|  |  | ||||||
| 	constructor() { | 	constructor() { | ||||||
| 		Player.DataReceivedEvent.AddCallback(this._dataReceivedEvent, this); | 		MainControl.DataReceivedEvent.AddCallback(this._dataReceivedEvent, this); | ||||||
| 	} | 	} | ||||||
| 	private _dataReceivedEvent(param: any[] = null): void { | 	private _dataReceivedEvent(param: any[] = null): void { | ||||||
| 		let type: MainControl.DataType = param[0]; | 		let type: MainControl.DataType = param[0]; | ||||||
| @@ -67,139 +53,8 @@ export default class MainControlData { | |||||||
| 	private _serverData(resp: INetResponse<any>): void { | 	private _serverData(resp: INetResponse<any>): void { | ||||||
| 		if (resp.IsValid) { | 		if (resp.IsValid) { | ||||||
| 			switch (resp.Method) { | 			switch (resp.Method) { | ||||||
| 				case "activity_com.sync": { |  | ||||||
| 					activityComSync(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "backpack.info": { |  | ||||||
| 					backpackInfo(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "chat.ban": { |  | ||||||
| 					setChatBanTime(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "chat.message": { |  | ||||||
| 					chatMessage(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "chat.log": { |  | ||||||
| 					chatLog(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "friend.allow_list": { |  | ||||||
| 					friendAllowList(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "friend.deny_list": { |  | ||||||
| 					friendDenyList(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "game.share": { |  | ||||||
| 					const { openLineShareGame } = confirmModalObj; |  | ||||||
| 					const data: ILineShareData = { |  | ||||||
| 						slotID: resp.Data[0], |  | ||||||
| 						winMilt: resp.Data[1] |  | ||||||
| 					}; |  | ||||||
| 					openLineShareGame(data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "game.sync": { | 				case "game.sync": { | ||||||
| 					Cocos.VicKing_Bridge.InGameGetUUID = true; | 					CoroutineV2.Single(gameSync()).Start(); | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "jackpot.get": { |  | ||||||
| 					const { handleOpen, setModalType } = modalObj; |  | ||||||
| 					const playerData: State = Player.data.getState(); |  | ||||||
| 					playerData.account.jackpotGet.push(...resp.Data); |  | ||||||
| 					Player.data.setState(playerData); |  | ||||||
| 					setModalType(ModalContentType.jackpot); |  | ||||||
| 					handleOpen(); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "jackpot.pool": { |  | ||||||
| 					const playerData: State = Player.data.getState(); |  | ||||||
| 					if (!Config.IsVite || MainControl.Instance.IsInGame) { |  | ||||||
| 						for (let i = 0; i < playerData.game.jackpotPool.length; i++) { |  | ||||||
| 							const oldJpData: [gameId: number, maxJPId: number, jp: number] = playerData.game.jackpotPool[i]; |  | ||||||
| 							let newJpData: [gameId: number, maxJPId: number, jp: number] = null; |  | ||||||
| 							for (let j = 0; j < resp.Data.length; j++) { |  | ||||||
| 								const [gameId, maxJPId, jp] = resp.Data[j]; |  | ||||||
| 								if (gameId === oldJpData[0]) { |  | ||||||
| 									newJpData = resp.Data[j]; |  | ||||||
| 									break; |  | ||||||
| 								} |  | ||||||
| 							} |  | ||||||
| 							if (!newJpData) { |  | ||||||
| 								JackpotPoolCallBack.DispatchCallback(oldJpData[0], 0); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					playerData.game.jackpotPool = resp.Data; |  | ||||||
| 					Player.data.setState(playerData); |  | ||||||
| 					if (!Config.IsVite || MainControl.Instance.IsInGame) { |  | ||||||
| 						for (let i = 0; i < playerData.game.jackpotPool.length; i++) { |  | ||||||
| 							const jpData: [gameId: number, maxJPId: number, jp: number] = playerData.game.jackpotPool[i]; |  | ||||||
| 							JackpotPoolCallBack.DispatchCallback(jpData[0], jpData[2]); |  | ||||||
| 						} |  | ||||||
| 					} else { |  | ||||||
| 						Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.UpdateJPPool, null); |  | ||||||
| 					} |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "maintain.info": { |  | ||||||
| 					const playerData: State = Player.data.getState(); |  | ||||||
| 					if (resp.Data) { |  | ||||||
| 						resp.Data[3] = NumberEx.plus(MainControl.Instance.NowTime, resp.Data[3]); |  | ||||||
| 						playerData.maintain = resp.Data; |  | ||||||
| 						CommonEventCallBack.DispatchCallback(CommonEventType.Maintenance, null); |  | ||||||
| 					} else { |  | ||||||
| 						playerData.maintain = undefined; |  | ||||||
| 					} |  | ||||||
| 					Player.data.setState(playerData); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "profile.info": { |  | ||||||
| 					profileInfo(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "resource.update": { |  | ||||||
| 					const resourceItems: IResourceItem[] = CSResource.GetResourceItemsFromServer(resp.Data); |  | ||||||
| 					UserData.DoResUpdate(resourceItems); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "resource.bankruptcy": { |  | ||||||
| 					Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.Bankruptcy, null); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "system.disconnect": { |  | ||||||
| 					this._disconnectErrorType = +resp.Data["c"]; |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "txn.new": { |  | ||||||
| 					txnNew(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "txn.center": { |  | ||||||
| 					txnCenter(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "txn.trade": { |  | ||||||
| 					txnTrade(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "txn.user_add": { |  | ||||||
| 					txnUserAdd(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "vip.info": { |  | ||||||
| 					vipInfo(resp.Data); |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 				case "vip.level": { |  | ||||||
| 					const playerData: State = Player.data.getState(); |  | ||||||
| 					playerData.vip.level = resp.Data; |  | ||||||
| 					Player.data.setState(playerData); |  | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
| 				default: | 				default: | ||||||
| @@ -207,10 +62,9 @@ export default class MainControlData { | |||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			switch (resp.Method) { | 			switch (resp.Method) { | ||||||
| 				case "chat.log": { | 				// case "": { | ||||||
| 					chatLog([null, null]); | 				// 	break; | ||||||
| 					break; | 				// } | ||||||
| 				} |  | ||||||
| 				default: | 				default: | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -1,8 +1,4 @@ | |||||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | import { IConfirmMessageData, modalObj } from "@/UIControl/ModalContext"; | ||||||
| import { IConfirmMessageData } from "@/UI/MessageBox/ConfirmMessage"; |  | ||||||
| import { confirmModalObj } from "@/UI/MessageBox/ConfirmModalContext"; |  | ||||||
| import { StringFormKey } from "@/define/formkey"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** 訊息框相關 */ | /** 訊息框相關 */ | ||||||
| export default class CSMessage { | export default class CSMessage { | ||||||
| @@ -10,7 +6,7 @@ export default class CSMessage { | |||||||
|  |  | ||||||
| 	/** 一個按鈕的訊息框 */ | 	/** 一個按鈕的訊息框 */ | ||||||
| 	public static CreateYesMsg(content: string, yesCallback: () => void = null, enterStr: string = null, title: string = null, textAlign: "center" | "left" | "right" = null) { | 	public static CreateYesMsg(content: string, yesCallback: () => void = null, enterStr: string = null, title: string = null, textAlign: "center" | "left" | "right" = null) { | ||||||
| 		enterStr = enterStr ? enterStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Confirm); | 		enterStr = enterStr ? enterStr : "確認"; | ||||||
| 		let data: IConfirmMessageData = { | 		let data: IConfirmMessageData = { | ||||||
| 			title: title, | 			title: title, | ||||||
| 			content: content, | 			content: content, | ||||||
| @@ -19,14 +15,14 @@ export default class CSMessage { | |||||||
| 			enterStr: enterStr, | 			enterStr: enterStr, | ||||||
| 			textAlign: textAlign | 			textAlign: textAlign | ||||||
| 		}; | 		}; | ||||||
| 		const { openOtherConfirm } = confirmModalObj; | 		const { handleOpen } = modalObj; | ||||||
| 		openOtherConfirm(data); | 		handleOpen(data); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** 兩個按鈕的訊息框 */ | 	/** 兩個按鈕的訊息框 */ | ||||||
| 	public static CreateYesNoMsg(content: string, yesCallback: () => void = null, noCallback: () => void = null, enterStr: string = null, title: string = null, cancelStr: string = null, textAlign: "center" | "left" | "right" = null) { | 	public static CreateYesNoMsg(content: string, yesCallback: () => void = null, noCallback: () => void = null, enterStr: string = null, title: string = null, cancelStr: string = null, textAlign: "center" | "left" | "right" = null) { | ||||||
| 		enterStr = enterStr ? enterStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Confirm); | 		enterStr = enterStr ? enterStr : "確認"; | ||||||
| 		cancelStr = cancelStr ? cancelStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Cancel); | 		cancelStr = cancelStr ? cancelStr : "取消"; | ||||||
| 		let data: IConfirmMessageData = { | 		let data: IConfirmMessageData = { | ||||||
| 			title: title, | 			title: title, | ||||||
| 			content: content, | 			content: content, | ||||||
| @@ -37,8 +33,8 @@ export default class CSMessage { | |||||||
| 			cancelStr: cancelStr, | 			cancelStr: cancelStr, | ||||||
| 			textAlign: textAlign | 			textAlign: textAlign | ||||||
| 		}; | 		}; | ||||||
| 		const { openOtherConfirm } = confirmModalObj; | 		const { handleOpen } = modalObj; | ||||||
| 		openOtherConfirm(data); | 		handleOpen(data); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** 網路錯誤訊息 */ | 	/** 網路錯誤訊息 */ | ||||||
|   | |||||||
| @@ -82,9 +82,9 @@ export class NetConnector { | |||||||
| 		// if (CC_DEBUG && NetConfig.ShowServerLog) { | 		// if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||||
| 		if (NetConfig.ShowServerLog) { | 		if (NetConfig.ShowServerLog) { | ||||||
| 			if (req.Data != null && req.Data != undefined && !Number.isNaN(req.Data)) { | 			if (req.Data != null && req.Data != undefined && !Number.isNaN(req.Data)) { | ||||||
| 				console.debug(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`); | 				console.log(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`); | ||||||
| 			} else { | 			} else { | ||||||
| 				console.debug(`[RPC] 傳送server資料: ${req.Method}()`); | 				console.log(`[RPC] 傳送server資料: ${req.Method}()`); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -185,9 +185,9 @@ export class NetConnector { | |||||||
| 				// if (CC_DEBUG && NetConfig.ShowServerLog) { | 				// if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||||
| 				if (NetConfig.ShowServerLog) { | 				if (NetConfig.ShowServerLog) { | ||||||
| 					if (data) { | 					if (data) { | ||||||
| 						console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); | 						console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); | ||||||
| 					} else { | 					} else { | ||||||
| 						console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); | 						console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								src/Engine/CatanEngine/NetManagerV2/NetManagerSD.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/Engine/CatanEngine/NetManagerV2/NetManagerSD.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { NetConnector } from "./NetConnector"; | ||||||
|  |  | ||||||
|  | export class NetManagerSD { | ||||||
|  | 	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<any, any>) { | ||||||
|  | 		this.CheckConnector(); | ||||||
|  | 		this._connector.Send(req); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 傳送資料給Server, 並等待回應 | ||||||
|  | 	 * @param req | ||||||
|  | 	 */ | ||||||
|  | 	static SendAsync(req: INetRequest<any, any>, mask: boolean) { | ||||||
|  | 		this.CheckConnector(); | ||||||
|  | 		return this._connector.SendAsync(req, mask); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static CheckConnector() { | ||||||
|  | 		if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector"); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { VueNetConnector } from "@/assets/VueScript/Net/VueNetConnector"; |  | ||||||
| import { INetRequest } from "./Core/INetRequest"; | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { NetManager } from "./NetManager"; | ||||||
|  |  | ||||||
| export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | ||||||
| 	abstract get Method(): string; | 	abstract get Method(): string; | ||||||
| @@ -11,18 +11,11 @@ export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TR | |||||||
| 	Data: TResquest; | 	Data: TResquest; | ||||||
| 	Result: import("./Core/INetResponse").INetResponse<TResponse>; | 	Result: import("./Core/INetResponse").INetResponse<TResponse>; | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 |  | ||||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 |  | ||||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 |  | ||||||
| 	 */ |  | ||||||
| 	SendAsync(mask: boolean = false): Iterator<any> { | 	SendAsync(mask: boolean = false): Iterator<any> { | ||||||
| 		// return NetManager.SendAsync(this, mask); | 		return NetManager.SendAsync(this, mask); | ||||||
| 		return VueNetConnector.SendAsync(this, mask); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	Send() { | 	Send() { | ||||||
| 		// NetManager.Send(this); | 		NetManager.Send(this); | ||||||
| 		VueNetConnector.Send(this); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/Engine/CatanEngine/NetManagerV2/NetRequestSD.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Engine/CatanEngine/NetManagerV2/NetRequestSD.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | import { INetRequest } from "./Core/INetRequest"; | ||||||
|  | import { NetManagerSD } from "./NetManagerSD"; | ||||||
|  |  | ||||||
|  | export abstract class NetRequestSD<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | ||||||
|  | 	abstract get Method(): string; | ||||||
|  |  | ||||||
|  | 	get MethodBack(): string { | ||||||
|  | 		return this.Method; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Data: TResquest; | ||||||
|  | 	Result: import("./Core/INetResponse").INetResponse<TResponse>; | ||||||
|  |  | ||||||
|  | 	SendAsync(mask: boolean = false): Iterator<any> { | ||||||
|  | 		return NetManagerSD.SendAsync(this, mask); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Send() { | ||||||
|  | 		NetManagerSD.Send(this); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -1,11 +1,9 @@ | |||||||
| import MainControl from "@/Common/MainControl/MainControl"; |  | ||||||
| import CSMessage from "@/Common/Message/CSMessage"; |  | ||||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; |  | ||||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; |  | ||||||
| import { useGameItems } from "@/context/GameItemsContext"; | import { useGameItems } from "@/context/GameItemsContext"; | ||||||
| import { CommonAccountResponse, LineLoginRequest } from "@/define/Request/RegisterRequest"; | import { Layout } from "antd"; | ||||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||||
| import { useNavigate } from "react-router-dom"; | import { useNavigate } from "react-router-dom"; | ||||||
|  | import Player from "./Lobby/Player"; | ||||||
|  | import SlotList from "./Lobby/SlotList"; | ||||||
|  |  | ||||||
| const Lobby = () => { | const Lobby = () => { | ||||||
| 	const { player, setPlayer } = useGameItems(); | 	const { player, setPlayer } = useGameItems(); | ||||||
| @@ -17,30 +15,6 @@ const Lobby = () => { | |||||||
| 			navigate(`/`); | 			navigate(`/`); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		CoroutineV2.Single(onStart()).Start(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	function* onStart() { |  | ||||||
| 		yield* MainControl.Instance.ConnectAsync(); |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
| 	function* registerLineLogin() { |  | ||||||
| 		let req: LineLoginRequest = new LineLoginRequest(token); |  | ||||||
| 		yield req.SendAsync(true); |  | ||||||
| 		let resp: INetResponse<CommonAccountResponse> = req.Result; |  | ||||||
| 		if (!resp.IsValid) { |  | ||||||
| 			//取得帳號失敗直接斷開SOCKET |  | ||||||
| 			if (resp.Status != 12) { |  | ||||||
| 				const msg: string = "Line Info Error. Error Code:" + req.Result.Status; |  | ||||||
| 				CSMessage.CreateYesMsg(msg); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 			console.warn("LINE帳號無綁定"); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		// yield* this.ServerAccountLogin(resp.Data.id, resp.Data.pw); |  | ||||||
|  |  | ||||||
| 		return; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	useEffect(() => { | 	useEffect(() => { | ||||||
| @@ -48,7 +22,10 @@ const Lobby = () => { | |||||||
| 	}, []); | 	}, []); | ||||||
|  |  | ||||||
| 	return ( | 	return ( | ||||||
| 		<>Lobby</> | 		<Layout hasSider style={{ height: "100%", position: "relative" }}> | ||||||
|  | 			<Player /> | ||||||
|  | 			{<SlotList />} | ||||||
|  | 		</Layout> | ||||||
| 	); | 	); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								src/UI/Lobby/Player.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/UI/Lobby/Player.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | import { CurrencyManager } from "@/FormTableExt/Manage/Currency/CurrencyManager"; | ||||||
|  | import { useGameItems } from "@/context/GameItemsContext"; | ||||||
|  | import { useEffect } from "react"; | ||||||
|  |  | ||||||
|  | const Player = () => { | ||||||
|  | 	const { player } = useGameItems(); | ||||||
|  | 	const { aId, name, m } = player; | ||||||
|  |  | ||||||
|  | 	function onLoad() { | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	useEffect(() => { | ||||||
|  | 		onLoad(); | ||||||
|  | 	}, []); | ||||||
|  |  | ||||||
|  | 	return ( | ||||||
|  | 		<div style={siderStyle}> | ||||||
|  | 			<p>aId: {aId}</p> | ||||||
|  | 			<p>暱稱: {name}</p> | ||||||
|  | 			<p>金幣: {CurrencyManager.GetNumberWithComma(m)}</p> | ||||||
|  | 		</div> | ||||||
|  | 	); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default Player; | ||||||
|  |  | ||||||
|  | const siderStyle: React.CSSProperties = { | ||||||
|  | 	fontSize: "1rem", | ||||||
|  | 	color: "#000000", | ||||||
|  | 	display: "flex", | ||||||
|  | 	textAlign: "left", | ||||||
|  | 	flexDirection: "column", | ||||||
|  | 	justifyContent: "center", | ||||||
|  | 	width: "20%" | ||||||
|  | }; | ||||||
							
								
								
									
										145
									
								
								src/UI/Lobby/SDGame.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/UI/Lobby/SDGame.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | |||||||
|  | import CSMessage from "@/Common/Message/CSMessage"; | ||||||
|  | import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
|  | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
|  | import { NetConnector } from "@/Engine/CatanEngine/NetManagerV2/NetConnector"; | ||||||
|  | import { NetManagerSD } from "@/Engine/CatanEngine/NetManagerV2/NetManagerSD"; | ||||||
|  | import { useGameItems } from "@/context/GameItemsContext"; | ||||||
|  | import SlotBase from "@/define/Game/Base/SlotBase"; | ||||||
|  | import { SDAccountLoginRequest } from "@/define/Request/AccountRequest"; | ||||||
|  | import { SlotInRequest } from "@/define/Request/SlotRequest"; | ||||||
|  | import { Button, Flex } from "antd"; | ||||||
|  | import { useEffect, useState } from "react"; | ||||||
|  |  | ||||||
|  | const SDGame = (props: ISDGame) => { | ||||||
|  | 	const { gameUrl, onClickSlotOut } = props; | ||||||
|  | 	const { player, setPlayer } = useGameItems(); | ||||||
|  | 	const { gameData } = useGameItems(); | ||||||
|  | 	const { nowSlotId } = gameData; | ||||||
|  | 	const [slotId, setSlotId] = useState<number>(undefined); | ||||||
|  | 	const [slotData, setSlotData] = useState<Object>(undefined); | ||||||
|  | 	let conn: NetConnector = undefined; | ||||||
|  |  | ||||||
|  | 	function* onLoad(): IterableIterator<any> { | ||||||
|  | 		const url: URL = new URL(gameUrl); | ||||||
|  | 		const queryParameters: URLSearchParams = new URLSearchParams(url.search); | ||||||
|  | 		const token: string = queryParameters.get("token"); | ||||||
|  | 		const slotid: number = +queryParameters.get("slotid"); | ||||||
|  | 		const host: string = queryParameters.get("host"); | ||||||
|  | 		const port: number = 9005; | ||||||
|  |  | ||||||
|  | 		setSlotId(slotid); | ||||||
|  | 		conn = new NetConnector("https://" + host, port); | ||||||
|  | 		conn.OnDataReceived.AddCallback(onNetDataReceived); | ||||||
|  | 		conn.OnDisconnected.AddCallback(onNetDisconnected); | ||||||
|  | 		NetManagerSD.Initialize(conn); | ||||||
|  | 		console.log("[SDsocket] connecting..."); | ||||||
|  | 		yield NetManagerSD.ConnectAsync(); | ||||||
|  | 		yield* login(token); | ||||||
|  | 		yield* slotIn(slotid); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* login(token: string): IterableIterator<any> { | ||||||
|  | 		const req = new SDAccountLoginRequest(token); | ||||||
|  | 		yield req.SendAsync(true); | ||||||
|  | 		const resp = req.Result; | ||||||
|  | 		if (!resp.IsValid) { | ||||||
|  | 			CSMessage.NetError(resp.Method, resp.Status, "SD Account Login Fail"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* slotIn(slotid: number): IterableIterator<any> { | ||||||
|  | 		let req: SlotInRequest = new SlotInRequest(slotid); | ||||||
|  | 		yield req.SendAsync(true); | ||||||
|  | 		let resp: INetResponse<JSON> = req.Result; | ||||||
|  | 		if (resp.IsValid) { | ||||||
|  | 			setSlotData(resp.Data); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	async function OnclickSpin() { | ||||||
|  | 		let slot: any; | ||||||
|  | 		const slotGroup: typeof import("../../define/Game/Base/Slot") = await import(/* @vite-ignore */`../../define/Game/Base/Slot`); | ||||||
|  | 		try { | ||||||
|  | 			slot = slotGroup[`Slot${slotId}`]; | ||||||
|  | 		} catch (error) { | ||||||
|  | 			// | ||||||
|  | 		} | ||||||
|  | 		if (!slot) { | ||||||
|  | 			slot = slotGroup.SlotBase; | ||||||
|  | 		} | ||||||
|  | 		const slotClass: SlotBase = new slot(slotId); | ||||||
|  | 		// this.IsSpin.value = true; | ||||||
|  | 		CoroutineV2.Single(spin(slotClass)).Start(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* spin(slotClass: SlotBase): IterableIterator<any> { | ||||||
|  | 		yield* slotClass.Spin(20); | ||||||
|  | 		// await Tools.Sleep(this.SpinDelay.value * 1000); | ||||||
|  | 		// if (this.IsSpin.value && this._bj_Casino_Bot.LobbyScript.IsSlotIn.value) { | ||||||
|  | 		//     this.Spin(); | ||||||
|  | 		// } else { | ||||||
|  | 		//     this.IsRun = false; | ||||||
|  | 		// } | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/**RPC回傳.若協定錯誤斷線.原因也會在這裡收到 */ | ||||||
|  | 	function onNetDataReceived(resp: INetResponse<any>) { | ||||||
|  | 		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.ServerData, resp]); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/**只要連線中斷不管主被動都會走到這裡 */ | ||||||
|  | 	function onNetDisconnected() { | ||||||
|  | 		console.warn("[socket] Disconnected"); | ||||||
|  | 		conn.OnDataReceived.RemoveAllCallbacks(); | ||||||
|  | 		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.NetDisconnected]); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	useEffect(() => { | ||||||
|  | 		CoroutineV2.Single(onLoad()).Start(); | ||||||
|  | 	}, []); | ||||||
|  |  | ||||||
|  | 	return (<> | ||||||
|  | 		<div style={siderStyle}> | ||||||
|  | 			<Flex gap="small" wrap="wrap"> | ||||||
|  | 				<div style={controlStyle}> | ||||||
|  | 					Bet: 20 | ||||||
|  | 					<p> | ||||||
|  | 						<Button type="primary" onClick={OnclickSpin} style={{ width: "20%" }}>Spin</Button> | ||||||
|  | 						<Button type="primary" danger onClick={onClickSlotOut} style={{ width: "20%" }}>離開機台</Button> | ||||||
|  | 					</p> | ||||||
|  | 				</div> | ||||||
|  | 				<div> | ||||||
|  | 					Log | ||||||
|  | 				</div> | ||||||
|  | 			</Flex> | ||||||
|  | 		</div> | ||||||
|  | 	</>); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default SDGame; | ||||||
|  |  | ||||||
|  | interface ISDGame { | ||||||
|  | 	gameUrl: string; | ||||||
|  | 	onClickSlotOut: () => void; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const siderStyle: React.CSSProperties = { | ||||||
|  | 	fontSize: "1rem", | ||||||
|  | 	color: "#000000", | ||||||
|  | 	display: "flex", | ||||||
|  | 	textAlign: "left", | ||||||
|  | 	flexDirection: "column", | ||||||
|  | 	justifyContent: "center", | ||||||
|  | 	width: "100%" | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const controlStyle: React.CSSProperties = { | ||||||
|  | 	fontSize: "1rem", | ||||||
|  | 	display: "flex", | ||||||
|  | 	textAlign: "left", | ||||||
|  | 	flexDirection: "column", | ||||||
|  | 	justifyContent: "center", | ||||||
|  | 	lineHeight: "30px", | ||||||
|  | 	width: "30%" | ||||||
|  | }; | ||||||
							
								
								
									
										93
									
								
								src/UI/Lobby/SlotList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/UI/Lobby/SlotList.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | |||||||
|  | import CSMessage from "@/Common/Message/CSMessage"; | ||||||
|  | import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
|  | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
|  | import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||||
|  | import BusinessTypeSetting from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||||
|  | import Image from "@/components/Image/Image"; | ||||||
|  | import { useGameItems } from "@/context/GameItemsContext"; | ||||||
|  | import { GameLaunchRequest, GameLeaveRequest, RpcGameLaunchResponse } from "@/define/Request/GameRequest"; | ||||||
|  | import { SlotData } from "@/define/gameData"; | ||||||
|  | import { Button, Flex } from "antd"; | ||||||
|  | import { useEffect, useState } from "react"; | ||||||
|  | import SDGame from "./SDGame"; | ||||||
|  |  | ||||||
|  | const SlotList = () => { | ||||||
|  | 	const { gameData, setGameData } = useGameItems(); | ||||||
|  | 	const { slotData, slotList, nowSlotId } = gameData; | ||||||
|  | 	const [isGameIn, setIsGameIn] = useState<boolean>(false); | ||||||
|  | 	const [gameUrl, setGameUrl] = useState<string>(""); | ||||||
|  |  | ||||||
|  | 	function onLoad() { | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* onClickSlotIn(slotId: number): IterableIterator<any> { | ||||||
|  | 		const data: SlotData = slotData[slotId]; | ||||||
|  | 		const [componyID] = data; | ||||||
|  | 		const req: GameLaunchRequest = new GameLaunchRequest(componyID, slotId); | ||||||
|  | 		yield req.SendAsync(); | ||||||
|  | 		const resp: INetResponse<RpcGameLaunchResponse> = req.Result; | ||||||
|  | 		if (!resp.IsValid) { | ||||||
|  | 			if (resp.Status === 18) { | ||||||
|  | 				CSMessage.CreateYesMsg(CSSettingsV3.prototype.CommonString(16)); | ||||||
|  | 			} | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		setIsGameIn(true); | ||||||
|  | 		const url: string = resp.Data; | ||||||
|  | 		setGameData({ | ||||||
|  | 			...gameData, | ||||||
|  | 			nowSlotId: slotId | ||||||
|  | 		}); | ||||||
|  | 		if (componyID === 2) { | ||||||
|  | 			setGameUrl(url); | ||||||
|  | 		} | ||||||
|  | 		else { | ||||||
|  | 			window.open(url, "_blank"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function onClickSlotOut() { | ||||||
|  | 		const gameLeaveReq: GameLeaveRequest = new GameLeaveRequest(nowSlotId); | ||||||
|  | 		gameLeaveReq.Send(); | ||||||
|  | 		setGameUrl(""); | ||||||
|  | 		setIsGameIn(false); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	useEffect(() => { | ||||||
|  | 		onLoad(); | ||||||
|  | 	}, []); | ||||||
|  |  | ||||||
|  | 	return (<> | ||||||
|  | 		{isGameIn | ||||||
|  | 			? <>{gameUrl | ||||||
|  | 				? <SDGame gameUrl={gameUrl} onClickSlotOut={onClickSlotOut} /> | ||||||
|  | 				: <Flex gap="small" wrap="wrap"> | ||||||
|  | 					<Button type="primary" onClick={onClickSlotOut}>離開機台</Button> | ||||||
|  | 				</Flex>}</> | ||||||
|  |  | ||||||
|  | 			: <div style={contentStyle}> | ||||||
|  | 				<Flex gap="small" wrap="wrap"> | ||||||
|  | 					{slotList.map((slotId: number, index: number) => | ||||||
|  | 						<Image key={index} width={80} height={80} src={`${BusinessTypeSetting.UseDownloadUrl}game/${slotId}/s`} | ||||||
|  | 							onClick={() => { CoroutineV2.Single(onClickSlotIn(slotId)).Start(); }} style={{ cursor: "pointer" }} /> | ||||||
|  | 					)} | ||||||
|  | 				</Flex> | ||||||
|  | 			</div> | ||||||
|  | 		} | ||||||
|  | 	</>); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default SlotList; | ||||||
|  |  | ||||||
|  | const contentStyle: React.CSSProperties = { | ||||||
|  | 	fontSize: "1rem", | ||||||
|  | 	minHeight: 120, | ||||||
|  | 	lineHeight: "120px", | ||||||
|  | 	color: "#000000", | ||||||
|  | 	display: "flex", | ||||||
|  | 	textAlign: "center", | ||||||
|  | 	flexDirection: "column", | ||||||
|  | 	justifyContent: "center", | ||||||
|  | 	width: "100%" | ||||||
|  | }; | ||||||
| @@ -1,5 +1,11 @@ | |||||||
|  | import MainControl from "@/Common/MainControl/MainControl"; | ||||||
|  | import CSMessage from "@/Common/Message/CSMessage"; | ||||||
|  | import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||||
|  | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
| import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||||
| import { useGameItems } from "@/context/GameItemsContext"; | import { useGameItems } from "@/context/GameItemsContext"; | ||||||
|  | import { AccountLoginRequest } from "@/define/Request/AccountRequest"; | ||||||
|  | import { CommonAccountResponse, LineLoginRequest } from "@/define/Request/RegisterRequest"; | ||||||
| import { Button, Cascader } from "antd"; | import { Button, Cascader } from "antd"; | ||||||
| import TextArea from "antd/es/input/TextArea"; | import TextArea from "antd/es/input/TextArea"; | ||||||
| import React, { useState } from "react"; | import React, { useState } from "react"; | ||||||
| @@ -17,7 +23,7 @@ const Login = () => { | |||||||
| 	const serverType: typeof BusinessEnum.ServerType = BusinessEnum.ServerType; | 	const serverType: typeof BusinessEnum.ServerType = BusinessEnum.ServerType; | ||||||
| 	const [type, setType] = useState<number>(BusinessEnum.ServerType.Internal_Dev); | 	const [type, setType] = useState<number>(BusinessEnum.ServerType.Internal_Dev); | ||||||
| 	const [isLogin, setIsLogin] = useState<boolean>(false); | 	const [isLogin, setIsLogin] = useState<boolean>(false); | ||||||
| 	const [token, SetToken] = useState(""); | 	const [token, SetToken] = useState("eyJhbGciOiJIUzI1NiJ9.Am-dhpCRUo9iBHYJ0kro12-zUlOyNAVOw9poXEkUV14hvkL2RPxVqqtrsYbS9_aoKep4EOFYROFTbv6MfVai7gomKdr07XkmTtADtkbchkfm-yuGXVzW1mYabf646_U66MnvXX2PHS-ATXDYYx5He9PJ-5lF9g5BmhtxUYPW98w.MGUUrFQbBeUBPDJeoKMilbqbg6IkwEqbu2oyJVSmw6M"); | ||||||
| 	const options: Option[] = []; | 	const options: Option[] = []; | ||||||
| 	for (let i = 0, names: string[] = Object.keys(serverType); i < names.length; i++) { | 	for (let i = 0, names: string[] = Object.keys(serverType); i < names.length; i++) { | ||||||
| 		const key: string = names[i]; | 		const key: string = names[i]; | ||||||
| @@ -29,11 +35,59 @@ const Login = () => { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	async function login() { | 	async function onClickLogin() { | ||||||
|  | 		if (!token) { | ||||||
|  | 			CSMessage.CreateYesMsg("請輸入token"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		setIsLogin(true); | 		setIsLogin(true); | ||||||
| 		await onLoad(type); | 		await onLoad(type); | ||||||
|  | 		CoroutineV2.Single(login()).Start(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* login() { | ||||||
|  | 		yield* MainControl.Instance.ConnectAsync(); | ||||||
|  | 		yield* registerLineLogin(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function* registerLineLogin() { | ||||||
|  | 		let req: LineLoginRequest = new LineLoginRequest(token); | ||||||
|  | 		yield req.SendAsync(true); | ||||||
|  | 		let resp: INetResponse<CommonAccountResponse> = req.Result; | ||||||
|  | 		if (!resp.IsValid) { | ||||||
|  | 			//取得帳號失敗直接斷開SOCKET | ||||||
|  | 			if (resp.Status != 12) { | ||||||
|  | 				const msg: string = "Line Info Error. Error Code:" + req.Result.Status; | ||||||
|  | 				CSMessage.CreateYesMsg(msg); | ||||||
|  | 				setIsLogin(false); | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 			console.warn("LINE帳號無綁定"); | ||||||
|  | 			setIsLogin(false); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		yield* serverAccountLogin(resp.Data.id, resp.Data.pw); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** 遊戲帳號登入取得玩家資料.統一登入時在刪除需要刪除的資料 */ | ||||||
|  | 	function* serverAccountLogin(a: string, pw: string, partner: string = null): IterableIterator<any> { | ||||||
|  | 		let hasAP: boolean = (a && a != "null" && a != "undefined" && pw && pw != "null" && pw != "undefined"); | ||||||
|  | 		if (!hasAP) { | ||||||
|  | 			CSMessage.CreateYesMsg("沒有帳號或密碼.請確認回傳接值."); | ||||||
|  | 			setIsLogin(false); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		let req: AccountLoginRequest = new AccountLoginRequest(a, pw, partner); | ||||||
|  | 		yield req.SendAsync(true); | ||||||
|  | 		let resp: INetResponse<any> = req.Result; | ||||||
|  | 		if (!resp.IsValid) { | ||||||
|  | 			CSMessage.CreateYesMsg("Login Account Error! Error Code : " + resp.Status); | ||||||
|  | 			setIsLogin(false); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		setPlayer({ | 		setPlayer({ | ||||||
| 			...player, | 			...player, | ||||||
|  | 			...resp.Data, | ||||||
| 			token: token | 			token: token | ||||||
| 		}); | 		}); | ||||||
| 		navigate(`/lobby/`); | 		navigate(`/lobby/`); | ||||||
| @@ -45,9 +99,9 @@ const Login = () => { | |||||||
| 				<div style={boxStyle2}> | 				<div style={boxStyle2}> | ||||||
| 					<Cascader defaultValue={[BusinessEnum.ServerType[BusinessEnum.ServerType.Internal_Dev]]} options={options} onChange={(v: string[]) => setType(+v[0])} /> | 					<Cascader defaultValue={[BusinessEnum.ServerType[BusinessEnum.ServerType.Internal_Dev]]} options={options} onChange={(v: string[]) => setType(+v[0])} /> | ||||||
| 					<br /> | 					<br /> | ||||||
| 					<TextArea rows={4} value={token} onChange={e => SetToken(e.target.value)} /> | 					Token: <TextArea rows={4} value={token} onChange={e => SetToken(e.target.value)} /> | ||||||
| 					<br /> | 					<br /> | ||||||
| 					<Button type="primary" onClick={login}>登入</Button> | 					<Button type="primary" onClick={onClickLogin}>登入</Button> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| 		}</> | 		}</> | ||||||
|   | |||||||
							
								
								
									
										75
									
								
								src/UIControl/ModalContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/UIControl/ModalContext.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | |||||||
|  | import { Modal } from "antd"; | ||||||
|  | import { ReactNode, createContext, useContext, useState } from "react"; | ||||||
|  |  | ||||||
|  | type ModalProviderProps = { | ||||||
|  | 	children: ReactNode; | ||||||
|  | }; | ||||||
|  | const ModalContext = createContext<IModal>(undefined); | ||||||
|  |  | ||||||
|  | export function useModal() { | ||||||
|  | 	return useContext(ModalContext); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export let modalObj: IModal = null; | ||||||
|  |  | ||||||
|  | export function ModalProvider({ children }: ModalProviderProps) { | ||||||
|  | 	const [isOpen, setIsOpen] = useState(false); | ||||||
|  | 	const [confirmData, setConfirmData] = useState<IConfirmMessageData>(undefined); | ||||||
|  |  | ||||||
|  | 	function handleOpen(data: IConfirmMessageData): void { | ||||||
|  | 		setConfirmData(data); | ||||||
|  | 		setIsOpen(true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const handleClose = () => setIsOpen(false); | ||||||
|  |  | ||||||
|  | 	function handleConfirm(): void { | ||||||
|  | 		confirmData?.handleConfirm && confirmData?.handleConfirm(); | ||||||
|  | 		handleClose(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function handleCancel(): void { | ||||||
|  | 		confirmData?.handleCancel && confirmData?.handleCancel(); | ||||||
|  | 		handleClose(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	const modal: IModal = modalObj = { | ||||||
|  | 		isOpen, | ||||||
|  | 		handleOpen, | ||||||
|  | 		handleClose, | ||||||
|  | 		confirmData, | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	return ( | ||||||
|  | 		<ModalContext.Provider value={modal}> | ||||||
|  | 			{children} | ||||||
|  | 			<Modal title={confirmData?.title} open={isOpen} onOk={handleConfirm} onCancel={handleCancel} cancelText={confirmData?.cancelStr} style={{ top: "40%" }}> | ||||||
|  | 				<p>{confirmData?.content}</p> | ||||||
|  | 			</Modal> | ||||||
|  | 		</ModalContext.Provider> | ||||||
|  | 	); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export interface IModal { | ||||||
|  | 	isOpen: boolean; | ||||||
|  | 	handleOpen: (data: IConfirmMessageData) => void; | ||||||
|  | 	handleClose: () => void; | ||||||
|  | 	confirmData: IConfirmMessageData; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface IConfirmMessageData { | ||||||
|  | 	title?: string; | ||||||
|  | 	subTitle?: string; | ||||||
|  | 	content?: string; | ||||||
|  | 	enterStr?: string; | ||||||
|  | 	cancelStr?: string; | ||||||
|  | 	isShowCancel?: boolean; | ||||||
|  | 	isOrangeButton?: boolean; | ||||||
|  | 	isNeedClickConfirmClosePanel?: boolean; | ||||||
|  | 	handleCancel?: () => unknown; | ||||||
|  | 	handleConfirm?: (...args: any) => unknown; | ||||||
|  | 	render?: (data?: any) => ReactNode; | ||||||
|  | 	newRender?: (data?: any) => JSX.Element; | ||||||
|  | 	textAlign?: "center" | "left" | "right"; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								src/components/Image/Image.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/components/Image/Image.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | import { fallImg } from "@/utils"; | ||||||
|  |  | ||||||
|  | interface AvatarProps extends React.ImgHTMLAttributes<HTMLImageElement> { } | ||||||
|  |  | ||||||
|  | /** 防止掉圖時 上個預設圖 */ | ||||||
|  | const Image = (props: AvatarProps) => { | ||||||
|  | 	function onError(event: any) { | ||||||
|  | 		event.target.src = fallImg; | ||||||
|  | 	} | ||||||
|  | 	return ( | ||||||
|  | 		<img {...props} onError={onError} /> | ||||||
|  | 	); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default Image; | ||||||
| @@ -1,5 +1,7 @@ | |||||||
|  | import MainControlData from "@/Common/DataReceived/MainControlData"; | ||||||
| import MainControl from "@/Common/MainControl/MainControl"; | import MainControl from "@/Common/MainControl/MainControl"; | ||||||
| import BusinessTypeSetting, { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | import BusinessTypeSetting, { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||||
|  | import { GameData } from "@/define/gameData"; | ||||||
| import { PlayerData } from "@/define/playerData"; | import { PlayerData } from "@/define/playerData"; | ||||||
| import { IGameItems } from "@/types"; | import { IGameItems } from "@/types"; | ||||||
| import { ReactNode, createContext, useContext, useState } from "react"; | import { ReactNode, createContext, useContext, useState } from "react"; | ||||||
| @@ -15,21 +17,20 @@ export function useGameItems() { | |||||||
| export let gameObj: IGameItems = null; | export let gameObj: IGameItems = null; | ||||||
|  |  | ||||||
| export function GameItemsProvider({ children }: GameItemsProviderProps) { | export function GameItemsProvider({ children }: GameItemsProviderProps) { | ||||||
| 	const [gameId, setGameId] = useState<number>(null); | 	const [player, setPlayer] = useState<PlayerData>(initPlayerData()); | ||||||
| 	const [player, setPlayer] = useState<PlayerData>({ | 	const [gameData, setGameData] = useState<GameData>(initGameData()); | ||||||
| 		token: "", |  | ||||||
| 	}); |  | ||||||
|  |  | ||||||
| 	const game: IGameItems = gameObj = { | 	const game: IGameItems = gameObj = { | ||||||
| 		onLoad, | 		onLoad, | ||||||
| 		gameId, |  | ||||||
| 		setGameId, |  | ||||||
| 		player, | 		player, | ||||||
| 		setPlayer | 		setPlayer, | ||||||
|  | 		gameData, | ||||||
|  | 		setGameData | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	async function onLoad(serverType: BusinessEnum.ServerType) { | 	async function onLoad(serverType: BusinessEnum.ServerType) { | ||||||
| 		new MainControl(); | 		new MainControl(); | ||||||
|  | 		new MainControlData(); | ||||||
| 		await Promise.all([ | 		await Promise.all([ | ||||||
| 			// 設定執行環境 | 			// 設定執行環境 | ||||||
| 			setBusinessType(serverType), | 			setBusinessType(serverType), | ||||||
| @@ -88,3 +89,27 @@ export function GameItemsProvider({ children }: GameItemsProviderProps) { | |||||||
| 		</GameItemsContext.Provider> | 		</GameItemsContext.Provider> | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function initPlayerData(): PlayerData { | ||||||
|  | 	return { | ||||||
|  | 		token: undefined, | ||||||
|  | 		aId: undefined, | ||||||
|  | 		f: undefined, | ||||||
|  | 		r: undefined, | ||||||
|  | 		rf: undefined, | ||||||
|  | 		name: undefined, | ||||||
|  | 		a: undefined, | ||||||
|  | 		m: 0, | ||||||
|  | 		lp: undefined, | ||||||
|  | 		tr: undefined, | ||||||
|  | 		lct: undefined | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function initGameData(): GameData { | ||||||
|  | 	return { | ||||||
|  | 		slotData: [], | ||||||
|  | 		slotList: [], | ||||||
|  | 		nowSlotId: undefined, | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								src/define/Game/Base/Slot.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/define/Game/Base/Slot.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | export * from "../Slot1"; | ||||||
|  | export * from "../Slot1201"; | ||||||
|  | export * from "../Slot1305"; | ||||||
|  | export * from "../Slot32"; | ||||||
|  | export * from "../Slot34"; | ||||||
|  | export * from "../Slot48"; | ||||||
|  | export * from "../Slot50"; | ||||||
|  | export * from "../Slot62"; | ||||||
|  | export * from "../Slot64"; | ||||||
|  | export * from "../Slot65"; | ||||||
|  | export * from "../Slot66"; | ||||||
|  | export * from "./SlotBase"; | ||||||
							
								
								
									
										192
									
								
								src/define/Game/Base/SlotBase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/define/Game/Base/SlotBase.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | import CSMessage from "@/Common/Message/CSMessage"; | ||||||
|  | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
|  | import { CommonSlotSpinRequest } from "../Request/CommonSlotRequest"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	// public get ID(): number { return this._bj_Casino_Bot.LobbyScript.Slot; } | ||||||
|  | 	public get FreeID(): number { return 1; } | ||||||
|  | 	public get FreeCount(): number { return +this.GameRunData["free"][1]; } | ||||||
|  | 	public get HasChoiceFreeGame(): boolean { return false; } | ||||||
|  | 	public get SlotReqRespIsCount(): boolean { return false; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return false; } | ||||||
|  | 	public GameRunData: JSON = null; | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  |  | ||||||
|  | 	//#region protected | ||||||
|  |  | ||||||
|  | 	protected id: number; | ||||||
|  |  | ||||||
|  | 	// protected _bj_Slot: BJ_Casino_Bot_Slot; | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  |  | ||||||
|  | 	//#region Lifecycle | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * | ||||||
|  | 	 */ | ||||||
|  | 	constructor(id: number) { | ||||||
|  | 		this.id = id; | ||||||
|  | 		this.onLoad(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public async onLoad(): Promise<void> { | ||||||
|  | 		// | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  |  | ||||||
|  | 	//#region Custom | ||||||
|  |  | ||||||
|  | 	public *Spin(bet: number): IterableIterator<any> { | ||||||
|  | 		let gameRunData: JSON = null; | ||||||
|  | 		let req: CommonSlotSpinRequest = new CommonSlotSpinRequest(this.id, bet); | ||||||
|  | 		yield req.SendAsync(); | ||||||
|  | 		let resp: INetResponse<JSON> = req.Result; | ||||||
|  | 		if (resp.IsValid) { | ||||||
|  | 			gameRunData = this.GameRunData = resp.Data; | ||||||
|  | 		} else { | ||||||
|  | 			CSMessage.NetError(resp.Method, resp.Status); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// public async Spin(): Promise<void> { | ||||||
|  | 	// 	let gameRunData: JSON = null; | ||||||
|  | 	// 	let req: CommonSlotSpinRequest = new CommonSlotSpinRequest(this.ID, this._bj_Slot.NowBet); | ||||||
|  | 	// 	await req.SendAsync(); | ||||||
|  | 	// 	let resp: INetResponse<JSON> = req.Result; | ||||||
|  | 	// 	if (resp.IsValid) { | ||||||
|  | 	// 		gameRunData = this.GameRunData = resp.Data; | ||||||
|  | 	// 	} else { | ||||||
|  | 	// 		CSMessage.NetError(resp.Method, resp.Status); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	let money: number = gameRunData["money"] ? +gameRunData["money"] : 0; | ||||||
|  | 	// 	let winMoney: number = 0; | ||||||
|  | 	// 	let winMoneyLog: string = ""; | ||||||
|  | 	// 	let freeLog: string = ""; | ||||||
|  | 	// 	let resources: any[] = gameRunData["get"]; | ||||||
|  | 	// 	let free: any = gameRunData["free"]; | ||||||
|  | 	// 	let choiceFreeGame: boolean = gameRunData["rs"] === 0; | ||||||
|  | 	// 	if (resources) { | ||||||
|  | 	// 		winMoney = this._getWinMoney(resources); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	if (choiceFreeGame && this.HasChoiceFreeGame) { | ||||||
|  | 	// 		free = true; | ||||||
|  | 	// 	} | ||||||
|  | 	// 	if (free) { | ||||||
|  | 	// 		let freeCount: number = await this._getFreeCount(); | ||||||
|  | 	// 		let fswinMoney: number = 0; | ||||||
|  | 	// 		let fsmoney: number = 0; | ||||||
|  | 	// 		[freeCount, fswinMoney, fsmoney] = await this.FreeSpin(freeCount); | ||||||
|  | 	// 		if (fsmoney > 0) { | ||||||
|  | 	// 			money = fsmoney; | ||||||
|  | 	// 		} | ||||||
|  | 	// 		if (fswinMoney > 0) { | ||||||
|  | 	// 			winMoney = fswinMoney; | ||||||
|  | 	// 		} | ||||||
|  | 	// 		freeLog = `, hasFree: ${freeCount}`; | ||||||
|  | 	// 	} | ||||||
|  | 	// 	if (winMoney > 0) { | ||||||
|  | 	// 		winMoneyLog = `, winMoney: ${winMoney}`; | ||||||
|  | 	// 	} | ||||||
|  | 	// 	this._bj_Casino_Bot.UserData.Money = money; | ||||||
|  | 	// 	this._bj_Casino_Bot.SetUI(); | ||||||
|  | 	// 	let ratio: number = winMoney > 0 ? NumberEx.divide(winMoney, this._bj_Slot.NowBet) : 0; | ||||||
|  | 	// 	if (this._bj_Slot.IsRatioStop.value && ratio >= this._bj_Slot.RatioStop.value) { | ||||||
|  | 	// 		this._bj_Slot.OnclickStop(); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	if (this._bj_Slot.IsCountStop.value && this._bj_Slot.CountStop.value === 0) { | ||||||
|  | 	// 		this._bj_Slot.OnclickStop(); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	if (ratio > 100) { | ||||||
|  | 	// 		this._bj_Casino_Bot.AddLog(`Slot${this.ID} Spin Bet: ${this._bj_Slot.NowBet}, Ratio: ${ratio}, Money: ${money}${winMoneyLog}${freeLog}`); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	// this._bj_Casino_Bot.AddLog(`Slot${this.ID} Spin Bet: ${this._bj_Slot.NowBet}, Money: ${money}${winMoneyLog}${freeLog}`); | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// public async FreeSpin(freeCount: number): Promise<number[]> { | ||||||
|  | 	// 	let fswinMoney: number = 0; | ||||||
|  | 	// 	let fsmoney: number = 0; | ||||||
|  | 	// 	for (let i: number = 0; i < freeCount; i++) { | ||||||
|  | 	// 		let gameRunData: JSON = null; | ||||||
|  | 	// 		let req: CommonSlotFgSpinRequest = new CommonSlotFgSpinRequest(this.ID); | ||||||
|  | 	// 		await req.SendAsync(); | ||||||
|  | 	// 		let resp: INetResponse<JSON> = req.Result; | ||||||
|  | 	// 		if (resp.IsValid) { | ||||||
|  | 	// 			gameRunData = resp.Data; | ||||||
|  | 	// 			if (this.HasRetriggerFreeSpin) { | ||||||
|  | 	// 				let retriggercount: number = this._getRetriggerFreeSpinCount(gameRunData); | ||||||
|  | 	// 				freeCount += retriggercount; | ||||||
|  | 	// 			} | ||||||
|  | 	// 			if (i === freeCount - 1) { | ||||||
|  | 	// 				let resources: any[] = gameRunData["get"]; | ||||||
|  | 	// 				if (resources) { | ||||||
|  | 	// 					fswinMoney = this._getWinMoney(resources); | ||||||
|  | 	// 				} | ||||||
|  | 	// 				fsmoney = gameRunData["money"] ? +gameRunData["money"] : 0; | ||||||
|  | 	// 			} | ||||||
|  | 	// 		} else { | ||||||
|  | 	// 			CSMessage.NetError(resp.Method, resp.Status); | ||||||
|  | 	// 		} | ||||||
|  | 	// 		// this._bj_Casino_Bot.AddLog(`Slot${this.ID} FreeSpin MaxCount: ${freeCount}, Count: ${i + 1}`); | ||||||
|  | 	// 	} | ||||||
|  | 	// 	return [freeCount, fswinMoney, fsmoney]; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// protected _getWinMoney(resources: any[]): number { | ||||||
|  | 	// 	for (let i: number = 0; i < resources.length; i++) { | ||||||
|  | 	// 		const resource: any[] = resources[i]; | ||||||
|  | 	// 		if (resource[0] === 1) { | ||||||
|  | 	// 			return resource[1]; | ||||||
|  | 	// 		} | ||||||
|  | 	// 	} | ||||||
|  | 	// 	return 0; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// protected _getRetriggerFreeSpinCount(gameRunData: JSON): number { | ||||||
|  | 	// 	if (gameRunData["free"]) { | ||||||
|  | 	// 		return gameRunData["free"][1]; | ||||||
|  | 	// 	} | ||||||
|  | 	// 	return 0; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// protected async _getFreeCount(): Promise<number> { | ||||||
|  | 	// 	if (this.HasChoiceFreeGame) { | ||||||
|  | 	// 		return await this._getChoiceFreeCount(); | ||||||
|  | 	// 	} else { | ||||||
|  | 	// 		return this.FreeCount; | ||||||
|  | 	// 	} | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// protected async _getChoiceFreeCount(): Promise<number> { | ||||||
|  | 	// 	let id: number = this._getFreeID(); | ||||||
|  | 	// 	let request: Slot_ChoiceRequest = new Slot_ChoiceRequest(id); | ||||||
|  | 	// 	await request.SendAsync(true); | ||||||
|  | 	// 	var result: INetResponse<number> = request.Result; | ||||||
|  | 	// 	if (result.IsValid) { | ||||||
|  | 	// 		if (this.SlotReqRespIsCount) { | ||||||
|  | 	// 			return result.Data; | ||||||
|  | 	// 		} else { | ||||||
|  | 	// 			let slotNameSetting: string = CSSettingsV3.Slotset[this.ID].NameSetting; | ||||||
|  | 	// 			let free_info_id: number = result.Data; | ||||||
|  | 	// 			let slotSetting: any = CSSettingsV3[slotNameSetting]; | ||||||
|  | 	// 			let freeInfo: any = slotSetting.FreeInfo; | ||||||
|  | 	// 			let count: number = freeInfo[free_info_id].Spins; | ||||||
|  | 	// 			return count; | ||||||
|  | 	// 		} | ||||||
|  | 	// 	} | ||||||
|  | 	// 	return 0; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	// protected _getFreeID(): number { | ||||||
|  | 	// 	return this.FreeID; | ||||||
|  | 	// } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default SlotBase; | ||||||
							
								
								
									
										78
									
								
								src/define/Game/Request/CommonSlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/define/Game/Request/CommonSlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  |  | ||||||
|  | //======================================================================================= | ||||||
|  |  | ||||||
|  | import { NetRequestSD } from "../../../Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||||
|  |  | ||||||
|  | /**共用MAIN SPIN協定 */ | ||||||
|  | export interface SpinRequest { | ||||||
|  | 	pay: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class CommonSlotSpinRequest extends NetRequestSD<SpinRequest, JSON> { | ||||||
|  | 	private _id: number = 0; | ||||||
|  |  | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot" + this._id + ".spin"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(slotId: number, totalBet: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = slotId; | ||||||
|  | 		this.Data = { | ||||||
|  | 			pay: totalBet, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class CommonSlotFgSpinRequest extends NetRequestSD<any, JSON> { | ||||||
|  | 	private _id: number = 0; | ||||||
|  |  | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot" + this._id + ".fgspin"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(slotId: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = slotId; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class CommonSlotCollectUnlockRequest extends NetRequestSD<any, JSON> { | ||||||
|  | 	private _id: number = 0; | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "collect" + this._id + ".unlock"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(slotId: number, grid: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = slotId; | ||||||
|  | 		this.Data = { | ||||||
|  | 			Grid: grid, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class CommonSlotCollectSpinRequest extends NetRequestSD<any, JSON> { | ||||||
|  | 	private _id: number = 0; | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "collect" + this._id + ".spin"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(slotId: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = slotId; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | /**賓果 ChangeSet協定 */ | ||||||
|  | export class CommonBingoChangeSet extends NetRequestSD<any, JSON> { | ||||||
|  | 	private _id: number = 0; | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot" + this._id + ".chset"; | ||||||
|  | 	} | ||||||
|  | 	constructor(slotId: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = slotId; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
							
								
								
									
										78
									
								
								src/define/Game/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/define/Game/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | |||||||
|  | import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||||
|  |  | ||||||
|  | //======================================================================================= | ||||||
|  | interface ChoiceRequest { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /**五龍選擇協定 */ | ||||||
|  | export class Slot_ChoiceRequest extends NetRequestSD<ChoiceRequest, number> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot.req"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(id: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = id; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | interface GmRequest { | ||||||
|  | 	pay: number; | ||||||
|  | 	slot: string; | ||||||
|  | 	type: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class Slot_GMRequest extends NetRequestSD<GmRequest, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot.gm"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	get MethodBack(): string { | ||||||
|  | 		return "slot" + this._id + ".spin"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private _id: number = 1; | ||||||
|  |  | ||||||
|  | 	constructor(id: number, totalBet: number, symbols: string, type: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = id; | ||||||
|  | 		this.Data = { | ||||||
|  | 			pay: totalBet, | ||||||
|  | 			slot: symbols, | ||||||
|  | 			type: type, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class Bingo_GMRequest extends NetRequestSD<GmRequest, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "bingo.gm"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	get MethodBack(): string { | ||||||
|  | 		return "slot" + this._id + ".spin"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private _id: number = 0; | ||||||
|  |  | ||||||
|  | 	constructor(id: number, totalBet: number, bingos: string, type: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this._id = id; | ||||||
|  | 		this.Data = { | ||||||
|  | 			pay: totalBet, | ||||||
|  | 			slot: bingos, | ||||||
|  | 			type: type, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | /**前後端金額對不上協定 */ | ||||||
|  | export class Slot_ErrorRequest extends NetRequestSD<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot.error"; | ||||||
|  | 	} | ||||||
|  | 	constructor() { | ||||||
|  | 		super(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot1 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get ID(): number { return 1; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot1; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1201.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1201.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot1201 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get FreeCount(): number { return +this.GameRunData["free"]; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot1201; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1305.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1305.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot1305 extends SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	public get ID(): number { return 1305; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot1305; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot32.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot32.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot32 extends SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	public get ID(): number { return 32; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot32; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot34.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot34.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot34 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get ID(): number { return 34; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot34; | ||||||
							
								
								
									
										16
									
								
								src/define/Game/Slot48.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/define/Game/Slot48.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot48 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get ID(): number { return 48; } | ||||||
|  |     public get FreeID(): number { return 3; } | ||||||
|  |     public get HasChoiceFreeGame(): boolean { return true; } | ||||||
|  |     public get SlotReqRespIsCount(): boolean { return true; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot48; | ||||||
							
								
								
									
										15
									
								
								src/define/Game/Slot50.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/define/Game/Slot50.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot50 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get ID(): number { return 50; } | ||||||
|  |     public get FreeID(): number { return 1; } | ||||||
|  |     public get HasChoiceFreeGame(): boolean { return true; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot50; | ||||||
							
								
								
									
										31
									
								
								src/define/Game/Slot62.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/define/Game/Slot62.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot62 extends SlotBase { | ||||||
|  |     //#region public | ||||||
|  |  | ||||||
|  |     public get ID(): number { return 62; } | ||||||
|  |     public get FreeID(): number { return 3; } | ||||||
|  |     public get HasChoiceFreeGame(): boolean { return true; } | ||||||
|  |     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Custom | ||||||
|  |  | ||||||
|  |     protected _getFreeID(): number { | ||||||
|  |         let gameRunData: JSON = this.GameRunData; | ||||||
|  |         let scatterAmount: number = gameRunData["scatter"][0][0].length; | ||||||
|  |         if (scatterAmount > 4) { | ||||||
|  |             return 5; | ||||||
|  |         } else if (scatterAmount > 3) { | ||||||
|  |             return 4; | ||||||
|  |         } else { | ||||||
|  |             return this.FreeID; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot62; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot64.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot64.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot64 extends SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	public get ID(): number { return 64; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot64; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot65.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot65.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot65 extends SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	public get ID(): number { return 65; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot65; | ||||||
							
								
								
									
										13
									
								
								src/define/Game/Slot66.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot66.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | import SlotBase from "./Base/SlotBase"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | export class Slot66 extends SlotBase { | ||||||
|  | 	//#region public | ||||||
|  |  | ||||||
|  | 	public get ID(): number { return 66; } | ||||||
|  | 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||||
|  |  | ||||||
|  | 	//#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default Slot66; | ||||||
							
								
								
									
										9
									
								
								src/define/GameData.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/define/GameData.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | interface GameData { | ||||||
|  | 	slotData: SlotData[]; | ||||||
|  | 	slotList: number[]; | ||||||
|  | 	nowSlotId: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export type SlotData = [componyID: number, slotId: number, vip: number, status: number, tag: number] | ||||||
|  |  | ||||||
|  | export { type GameData }; | ||||||
| @@ -1,5 +1,15 @@ | |||||||
| interface PlayerData { | interface PlayerData { | ||||||
| 	token: string; | 	token: string; | ||||||
|  | 	aId: number; | ||||||
|  | 	f: number; | ||||||
|  | 	r: number; | ||||||
|  | 	rf: number; | ||||||
|  | 	name: string; | ||||||
|  | 	a: number; | ||||||
|  | 	m: number; | ||||||
|  | 	lp: number; | ||||||
|  | 	tr: number; | ||||||
|  | 	lct: number; | ||||||
| } | } | ||||||
|  |  | ||||||
| export { type PlayerData }; | export { type PlayerData }; | ||||||
|   | |||||||
							
								
								
									
										311
									
								
								src/define/Request/AccountRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								src/define/Request/AccountRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | |||||||
|  | import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||||
|  | import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest"; | ||||||
|  |  | ||||||
|  | // ======================================================================================= | ||||||
|  | /** 通用回傳SERVER創的遊戲帳號 */ | ||||||
|  | export interface CommonAccountResponse { | ||||||
|  | 	id: string; | ||||||
|  | 	pw: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ======================================================================================= | ||||||
|  | interface CreateResquest { | ||||||
|  | 	p: number; | ||||||
|  | 	d: string; | ||||||
|  | } | ||||||
|  | /** 直接玩(訪客給SERVER創帳號) */ | ||||||
|  | export class AccountCreateRequest extends NetRequest<CreateResquest, CommonAccountResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "account.create"; | ||||||
|  | 	} | ||||||
|  | 	/*constructor() { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			p: Config.GetRunDevice(), | ||||||
|  | 			d: LocalStorageData.Instance.ComboDeviceID, | ||||||
|  | 		}; | ||||||
|  | 	}*/ | ||||||
|  | } | ||||||
|  | // ======================================================================================= | ||||||
|  | interface LoginRequest { | ||||||
|  | 	// p: number; | ||||||
|  | 	// d: string; | ||||||
|  | 	// fcm_token: string; | ||||||
|  | 	id: number; | ||||||
|  | 	pw: string; | ||||||
|  | 	pl: number; | ||||||
|  | 	// ver: string; | ||||||
|  | } | ||||||
|  | interface LoginResponse { | ||||||
|  | 	pr: string; | ||||||
|  | 	cu: string; | ||||||
|  | } | ||||||
|  | /** 通用登入 */ | ||||||
|  | export class AccountLoginRequest extends NetRequest<LoginRequest, LoginResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "account.login"; | ||||||
|  | 	} | ||||||
|  | 	constructor(account: string, password: string, partner: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			id: +account, | ||||||
|  | 			pw: password, | ||||||
|  | 			pl: 3 | ||||||
|  | 		}; | ||||||
|  | 		if (partner) { | ||||||
|  | 			this.Data["pn"] = partner; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | interface SDLoginRequest { | ||||||
|  | 	token: string; | ||||||
|  | } | ||||||
|  | export class SDAccountLoginRequest extends NetRequestSD<SDLoginRequest, LoginResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "account.login"; | ||||||
|  | 	} | ||||||
|  | 	constructor(token: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			token: token, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ======================================================================================= | ||||||
|  | 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<string, CommonAccountResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "register.account_login"; | ||||||
|  | 	} | ||||||
|  | 	constructor(account: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = account; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ======================================================================================= | ||||||
|  | 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 class PhoneCheck extends NetRequest<PhoneCodeRequest, string> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "register.phone_check"; | ||||||
|  | 	} | ||||||
|  | 	constructor(p: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			p: p | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | /** 電話驗證 */ | ||||||
|  | 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, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface ChangePasswordInfo { | ||||||
|  | 	a: string; | ||||||
|  | 	opw: string; | ||||||
|  | 	pw: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** 修改密碼 */ | ||||||
|  | export class ChangePassword extends NetRequest<ChangePasswordInfo, null> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "register.account_change"; | ||||||
|  | 	} | ||||||
|  | 	constructor(account: string, prePassword: string, password: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			a: account, | ||||||
|  | 			opw: prePassword, | ||||||
|  | 			pw: password | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ======================================================================================= | ||||||
|  | export interface LineBindResponse { | ||||||
|  | 	n: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export class LineBind extends NetRequest<string, LineBindResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "register.line_bind"; | ||||||
|  | 	} | ||||||
|  | 	constructor(token: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = token; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | /** LINE登入(回傳SERVER帳號) */ | ||||||
|  | export class LineLoginRequest extends NetRequest<string, CommonAccountResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "register.line_login"; | ||||||
|  | 	} | ||||||
|  | 	constructor(token: string) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = token; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ======================================================================================= | ||||||
| @@ -3,6 +3,15 @@ import { NetRequest } from "@/Engine/CatanEngine/NetManagerV2/NetRequest"; | |||||||
|  |  | ||||||
| // #region Request | // #region Request | ||||||
|  |  | ||||||
|  | export type RpcGamInfoResponse = JSON | ||||||
|  | export class GameInfoRequest extends NetRequest<null, RpcGamInfoResponse> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "game.info"; | ||||||
|  | 	} | ||||||
|  | 	constructor() { | ||||||
|  | 		super(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| export type RpcGameLaunchRequest = number[] | export type RpcGameLaunchRequest = number[] | ||||||
| export type RpcGameLaunchResponse = string | export type RpcGameLaunchResponse = string | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								src/define/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/define/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||||
|  | import { LanguageManager } from "@/FormTableExt/Manage/Language/LanguageManager"; | ||||||
|  | import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest"; | ||||||
|  |  | ||||||
|  | //======================================================================================= | ||||||
|  | /**取得歷史紀錄網頁網址協定 */ | ||||||
|  | export class HistoryRequest extends NetRequest<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "history.url"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	constructor(slotId: number) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			slot: slotId, | ||||||
|  | 			lang: LanguageManager.UseLanguageUrlStr, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class SlotInRequest extends NetRequestSD<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot.in"; | ||||||
|  | 	} | ||||||
|  | 	constructor(slotid: number, hall: number = 0, uid: number = 0) { | ||||||
|  | 		super(); | ||||||
|  | 		this.Data = { | ||||||
|  | 			id: slotid | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class SlotOutRequest extends NetRequest<null, null> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "slot.out"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class FishOutRequest extends NetRequest<null, null> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "fish.out"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class TableOutRequest extends NetRequest<null, null> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "table.out"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class Table3002OutRequest extends NetRequest<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "two_sicbo.leave"; | ||||||
|  | 	} | ||||||
|  | 	constructor() { | ||||||
|  | 		super(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class Table3003OutRequest extends NetRequest<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "nine_sicbo.leave"; | ||||||
|  | 	} | ||||||
|  | 	constructor() { | ||||||
|  | 		super(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class Table3012OutRequest extends NetRequest<any, JSON> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "triple_baccarat.leave"; | ||||||
|  | 	} | ||||||
|  | 	constructor() { | ||||||
|  | 		super(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
|  | export class PinBallOutRequest extends NetRequest<null, null> { | ||||||
|  | 	get Method(): string { | ||||||
|  | 		return "pinball.out"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | //======================================================================================= | ||||||
| @@ -12,6 +12,7 @@ import { BaseEnumerator } from "./Engine/CatanEngine/CoroutineV2/Core/BaseEnumer | |||||||
| import Game from "./UI/Game"; | import Game from "./UI/Game"; | ||||||
| import Lobby from "./UI/Lobby"; | import Lobby from "./UI/Lobby"; | ||||||
| import Login from "./UI/Login"; | import Login from "./UI/Login"; | ||||||
|  | import { ModalProvider } from "./UIControl/ModalContext"; | ||||||
| import "./index.css"; | import "./index.css"; | ||||||
| import "./utils/catan"; | import "./utils/catan"; | ||||||
|  |  | ||||||
| @@ -35,7 +36,9 @@ const browserRouter: Router = createBrowserRouter(router); | |||||||
| const hashRouter: Router = createHashRouter(router); | const hashRouter: Router = createHashRouter(router); | ||||||
|  |  | ||||||
| ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( | ||||||
|  | 	<ModalProvider> | ||||||
| 		<GameItemsProvider> | 		<GameItemsProvider> | ||||||
| 			<RouterProvider router={browserRouter} /> | 			<RouterProvider router={browserRouter} /> | ||||||
| 		</GameItemsProvider> | 		</GameItemsProvider> | ||||||
|  | 	</ModalProvider> | ||||||
| ); | ); | ||||||
|   | |||||||
| @@ -1,10 +1,11 @@ | |||||||
| import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||||
|  | import { GameData } from "@/define/gameData"; | ||||||
| import { PlayerData } from "@/define/playerData"; | import { PlayerData } from "@/define/playerData"; | ||||||
|  |  | ||||||
| export interface IGameItems { | export interface IGameItems { | ||||||
| 	onLoad: (serverType: BusinessEnum.ServerType) => Promise<void>; | 	onLoad: (serverType: BusinessEnum.ServerType) => Promise<void>; | ||||||
| 	gameId: number; |  | ||||||
| 	setGameId: (v: number) => void; |  | ||||||
| 	player: PlayerData; | 	player: PlayerData; | ||||||
| 	setPlayer: (v: PlayerData) => void; | 	setPlayer: (v: PlayerData) => void; | ||||||
|  | 	gameData: GameData; | ||||||
|  | 	setGameData: (v: GameData) => void; | ||||||
| } | } | ||||||
| @@ -1,652 +1 @@ | |||||||
| import { ResourceItemType } from "@/Common/ResourceItem/ResourceItemType"; | export const fallImg: string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="; | ||||||
| import { BaseEnumerator } from "@/Engine/CatanEngine/CoroutineV2/Core/BaseEnumerator"; |  | ||||||
| import { TableManager } from "@/Engine/CatanEngine/TableV3/TableManager"; |  | ||||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; |  | ||||||
| import { ShopMycardTableRow, ShopShow2TableRow } from "@/FormTable/Tables/ShopTable"; |  | ||||||
| import { Cocos } from "@/assets/VueScript/Cocos"; |  | ||||||
| import { CocosVueScript } from "@/assets/VueScript/CocosVueScript"; |  | ||||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; |  | ||||||
| import { FriendRequest } from "@/define/Request/FriendRequest"; |  | ||||||
| import { TxnRequest } from "@/define/Request/TxnRequest"; |  | ||||||
| import { VIPLevelMapForChat } from "@/map"; |  | ||||||
| import Player from "@/modules/player"; |  | ||||||
| import { UserBindFlag } from "@/modules/player/define/userbind_flag"; |  | ||||||
| import { ChatRoomRole, Games, ItemCodeList, ItemPropsType, ItemSize, PriceList, SelectorItemProps, StringContentType, TagTypes, TxnCenterData } from "@/types"; |  | ||||||
| import liff from "@line/liff"; |  | ||||||
| import axios, { AxiosResponse } from "axios"; |  | ||||||
| import { isMobile } from "react-device-detect"; |  | ||||||
| import * as Scroll from "react-scroll"; |  | ||||||
| import stringWidth from "string-width"; |  | ||||||
| import BusinessTypeSetting, { FolderName } from "../_BusinessTypeSetting/BusinessTypeSetting"; |  | ||||||
|  |  | ||||||
| export const transArray = <T>(array: T[], split: number): T[][] => { |  | ||||||
| 	const newArr = []; |  | ||||||
| 	const copiedArr = array ? array?.slice() : []; |  | ||||||
| 	const length = copiedArr?.length; |  | ||||||
| 	for (let i = 0, j = 0; i < length; i += split, j++) { |  | ||||||
| 		newArr[j] = copiedArr.splice(0, split); |  | ||||||
| 	} |  | ||||||
| 	return newArr; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /** 去掉英文+百分比% */ |  | ||||||
| export function onlyNumber(stringText: string): number { |  | ||||||
| 	const str = +stringText.replace(/[A-Za-z%]/g, ""); |  | ||||||
| 	return str; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function wordsLimit(limit: number, string: string) { |  | ||||||
| 	const length = string?.length; |  | ||||||
| 	const isOverLimit = length > limit; |  | ||||||
| 	const result = isOverLimit ? "..." : ""; |  | ||||||
| 	return string?.substring(0, limit) + result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const capitalize = (str: string) => |  | ||||||
| 	`${str.charAt(0).toUpperCase()}${str.slice(1)}`; |  | ||||||
|  |  | ||||||
| export function checkForUnique(str: string): boolean { |  | ||||||
| 	const chineseCharacterMatch = |  | ||||||
| 		/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu; |  | ||||||
| 	const arr = str.match(chineseCharacterMatch); |  | ||||||
| 	if (arr === null) return true; |  | ||||||
| 	return !hasDuplicates(arr); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function onlyChinese(str: string) { |  | ||||||
| 	const chineseCharacterMatch = |  | ||||||
| 		/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu; |  | ||||||
| 	const arr = str.match(chineseCharacterMatch); |  | ||||||
| 	return arr.join(""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function hasDuplicates(array: string[]): boolean { |  | ||||||
| 	return new Set(array).size !== array.length; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function generatePriceList( |  | ||||||
| 	arr: [ID: number, ProductId: number, ShowMoney: number][], |  | ||||||
| 	items: { [id: string]: [ID: number, price: number] }, |  | ||||||
| 	priceRef: ShopMycardTableRow[], |  | ||||||
| 	itemCodeList?: Map<number, ItemCodeList>, |  | ||||||
| ): PriceList[] { |  | ||||||
| 	if (itemCodeList) { |  | ||||||
| 		arr = arr.filter((item) => itemCodeList.has(item[0])); |  | ||||||
| 	} |  | ||||||
| 	const MyCardPriceRefMap = new Map<number, number>( |  | ||||||
| 		priceRef.map((item) => [item.Id, item.Price]), |  | ||||||
| 	); |  | ||||||
| 	const newArr: [ID: number, ProductId: number, ShowMoney: number][] = []; |  | ||||||
| 	for (const item of Object.values(items)) { |  | ||||||
| 		arr.forEach((v: [ID: number, ProductId: number, ShowMoney: number]) => { |  | ||||||
| 			if (v[1] === item[0]) { |  | ||||||
| 				newArr.push(v); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| 	return newArr |  | ||||||
| 		.map((item) => ({ |  | ||||||
| 			ID: item[0], |  | ||||||
| 			points: item[2], |  | ||||||
| 			price: MyCardPriceRefMap.get(item[1]), |  | ||||||
| 		})) |  | ||||||
| 		.sort((a, b) => b.price - a.price); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** 支付列表 */ |  | ||||||
| export function generatePaymentList( |  | ||||||
| 	arr: string[], |  | ||||||
| 	priceRef: ShopShow2TableRow[], |  | ||||||
| ): ShopShow2TableRow[] { |  | ||||||
| 	const newArr: ShopShow2TableRow[] = []; |  | ||||||
| 	for (const item of Object.values(priceRef)) { |  | ||||||
| 		arr.forEach((x) => { |  | ||||||
| 			if (item.Show && x === item.Key) newArr.push(item); |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// priceRef.forEach((value: ShopShow2TableRow) =>  { |  | ||||||
| 	// 	arr.includes(value.Key); |  | ||||||
| 	// }) |  | ||||||
| 	return newArr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** getQueryParameters */ |  | ||||||
| export function getQueryParameters(v: string): string { |  | ||||||
| 	const queryParameters = new URLSearchParams(location.search); |  | ||||||
| 	return queryParameters.get(v); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function createMap(obj: unknown) { |  | ||||||
| 	return new Map(Object.entries(obj)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function isArray(itemCode: string | string[]): boolean { |  | ||||||
| 	return Array.isArray(itemCode); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function formatTime(date: Date): string { |  | ||||||
| 	const hours = date.getHours(); |  | ||||||
| 	const minutes = date.getMinutes(); |  | ||||||
| 	const amPm = hours >= 12 ? "pm" : "am"; |  | ||||||
| 	const formattedHours = hours % 12 === 0 ? 12 : hours % 12; |  | ||||||
| 	const formattedMinutes = minutes < 10 ? "0" + minutes : minutes; |  | ||||||
| 	return `${formattedHours}:${formattedMinutes} ${amPm}`; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getCurrentLocalTime() { |  | ||||||
| 	const date = new Date(); |  | ||||||
| 	const utcTime = date.getTime(); |  | ||||||
| 	return new Date(utcTime).toLocaleTimeString(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function transferColorText(str: string): string { |  | ||||||
| 	const regex = /color=/g; |  | ||||||
| 	const replacement = "span style=color:"; |  | ||||||
| 	const result = str.replace(regex, replacement); |  | ||||||
| 	const regex2 = /color>/g; |  | ||||||
| 	const replacement2 = "span>"; |  | ||||||
| 	return result.replace(regex2, replacement2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function generateItemsData( |  | ||||||
| 	games: Map<string, number[]>, |  | ||||||
| 	favoriteGames: number[], |  | ||||||
| ): ItemPropsType[] { |  | ||||||
| 	let itemsData: boolean | ItemPropsType[] = []; |  | ||||||
| 	const s = new Set(favoriteGames); |  | ||||||
| 	if (games.size) { |  | ||||||
| 		// @ts-ignore |  | ||||||
| 		for (const [gameID, [vendorID, id, VIPLimit, status, tag]] of games) { |  | ||||||
| 			const dataObj: ItemPropsType = { |  | ||||||
| 				id: gameID, |  | ||||||
| 				vendorID: vendorID.toString(), |  | ||||||
| 				img: { |  | ||||||
| 					url: `${BusinessTypeSetting.UseDownloadUrl}${FolderName.Game}${id}/b`, |  | ||||||
| 				}, |  | ||||||
| 				size: ItemSize.small, |  | ||||||
| 				tag: tag as unknown as TagTypes, |  | ||||||
| 				lockBtn: VIPLimit, |  | ||||||
| 				like: s.has(id), |  | ||||||
| 				status, |  | ||||||
| 			}; |  | ||||||
|  |  | ||||||
| 			itemsData.push(dataObj); |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		itemsData = []; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return itemsData; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function generateItemsDataMap(games: Games): Map<string, number[]> { |  | ||||||
| 	const map = new Map(); |  | ||||||
| 	for (const [gameID, value] of Object.entries(games)) { |  | ||||||
| 		map.set(gameID, value); |  | ||||||
| 	} |  | ||||||
| 	return map; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function sortedGames(sorts: number[], map: Map<string, number[]>) { |  | ||||||
| 	const obj = new Map(); |  | ||||||
| 	sorts?.forEach((gameID) => { |  | ||||||
| 		obj.set("" + gameID, map?.get("" + gameID)); |  | ||||||
| 	}); |  | ||||||
| 	return obj; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function addPropertiesToDefaultItem( |  | ||||||
| 	games: any[], |  | ||||||
| 	selectedID: number, |  | ||||||
| ): SelectorItemProps[] { |  | ||||||
| 	const index = games.findIndex((item) => parseInt(item.id) === selectedID); |  | ||||||
| 	const newGames = games.slice(); |  | ||||||
|  |  | ||||||
| 	return newGames.map((g, i) => |  | ||||||
| 		i === index |  | ||||||
| 			? { ...g, selected: true, defaultItem: true } |  | ||||||
| 			: { |  | ||||||
| 				...g, |  | ||||||
| 				selected: false, |  | ||||||
| 				defaultItem: false, |  | ||||||
| 			}, |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function switchObjToMap(games: Games) { |  | ||||||
| 	// for (const [gameID, value] of Object.entries(games)) { |  | ||||||
| 	//   map.set(gameID, value) |  | ||||||
| 	// } |  | ||||||
| 	return new Map(Object.entries(games)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function hexToRgb( |  | ||||||
| 	hex: string, |  | ||||||
| 	// eslint-disable-next-line @typescript-eslint/typedef |  | ||||||
| 	result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex), |  | ||||||
| ) { |  | ||||||
| 	const x = result ? result.map((i) => parseInt(i, 16)).slice(1) : null; |  | ||||||
| 	return { |  | ||||||
| 		r: x[0], |  | ||||||
| 		g: x[1], |  | ||||||
| 		b: x[2], |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function replaceBorderColor(string: string, color: string) { |  | ||||||
| 	const hasComma = string.includes(","); |  | ||||||
| 	if (hasComma) { |  | ||||||
| 		const result = string.split(",").map((s, i) => { |  | ||||||
| 			const index = s.indexOf("#"); |  | ||||||
| 			const replaceStr = s.substring(index); |  | ||||||
| 			return s.replace(replaceStr, i === 0 ? "black" : color); |  | ||||||
| 		}); |  | ||||||
| 		return result.join(","); |  | ||||||
| 	} else { |  | ||||||
| 		const index = string.indexOf("#"); |  | ||||||
| 		const replaceStr = string.substring(index); |  | ||||||
| 		return string.replace(replaceStr, color); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function generateMessage(message: string) { |  | ||||||
| 	return { |  | ||||||
| 		AID: "10000000063", |  | ||||||
| 		nickName: "masterkai", |  | ||||||
| 		profileIMG: "./img/png/avatar.png", |  | ||||||
| 		role: ChatRoomRole.player, |  | ||||||
| 		message: message, |  | ||||||
| 		created: getCurrentLocalTime(), |  | ||||||
| 		vip: VIPLevelMapForChat.get(4), |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getVIPLevelFromStr(vipStr: string) { |  | ||||||
| 	const arr = vipStr.split("."); |  | ||||||
| 	const str = arr[0]; |  | ||||||
| 	return str.at(-1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| interface Accumulator { |  | ||||||
| 	[AID: number]: { |  | ||||||
| 		AID: number; |  | ||||||
| 		nickName: string; |  | ||||||
| 		avatar: number; |  | ||||||
| 		role: number; |  | ||||||
| 		vip: number; |  | ||||||
| 		messages: { |  | ||||||
| 			message: string; |  | ||||||
| 			created: number; |  | ||||||
| 		}[]; |  | ||||||
| 	}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function sleep(ms: any): Promise<any> { |  | ||||||
| 	return new Promise((resolve) => setTimeout(resolve, ms)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export async function downloadJSON(formname: string) { |  | ||||||
| 	const patchUrl: string = |  | ||||||
| 		BusinessTypeSetting.UsePatch + BusinessTypeSetting.FolderUrlJson; |  | ||||||
| 	let fileUrl: string = `${patchUrl}${formname}.json`; |  | ||||||
| 	fileUrl = fileUrl + "?v=" + Date.now(); |  | ||||||
| 	let resp: AxiosResponse<any, any> = null; |  | ||||||
| 	axios.get(fileUrl).then((res: AxiosResponse<any, any>) => { |  | ||||||
| 		loadJsonProcess(null, res, formname); |  | ||||||
| 		resp = res; |  | ||||||
| 	}); |  | ||||||
| 	while (!resp) { |  | ||||||
| 		await sleep(0.1); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function loadJsonProcess( |  | ||||||
| 	err: any, |  | ||||||
| 	res: AxiosResponse<any, any>, |  | ||||||
| 	formname: string, |  | ||||||
| ) { |  | ||||||
| 	res["name"] = formname; |  | ||||||
| 	TableManager.AddJsonAsset(res.data); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getProfileImgUrl(avatar: number, aId: number) { |  | ||||||
| 	return avatar === 1 |  | ||||||
| 		? `${BusinessTypeSetting.UseDownloadUrl}avatar/${aId}` |  | ||||||
| 		: "./img/common/DefaultAvatar.png"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const CssStringContent = ( |  | ||||||
| 	StringKey: number, |  | ||||||
| 	StringID: number | string, |  | ||||||
| ): string => { |  | ||||||
| 	switch (StringKey) { |  | ||||||
| 		case StringContentType.String: |  | ||||||
| 			return StringID?.toString(); |  | ||||||
| 		case StringContentType.CSSString: |  | ||||||
| 			return CSSettingsV3.prototype.CommonString(+StringID); |  | ||||||
| 		case StringContentType.CSSMailString: |  | ||||||
| 			return CSSettingsV3.prototype.CSSMailString(+StringID); |  | ||||||
| 		case StringContentType.CSSNetworkString: |  | ||||||
| 			return ""; // CSSettingsV3.Network.Priority[StringID][LanguageManager.GetMsgId()]; |  | ||||||
| 		case StringContentType.HallString: |  | ||||||
| 			/* 廳管1~4 但表格是從2號位開始 */ |  | ||||||
| 			return CSSettingsV3.prototype.LobbyString(1 + +StringID); |  | ||||||
|  |  | ||||||
| 		default: |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 	return; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export function txnDataTransformer( |  | ||||||
| 	arr: TxnRequest.TxnInfo[], |  | ||||||
| 	playerAid: number, |  | ||||||
| ): TxnCenterData[] { |  | ||||||
| 	return arr.map( |  | ||||||
| 		([ |  | ||||||
| 			sn, |  | ||||||
| 			time, |  | ||||||
| 			giver, |  | ||||||
| 			receiver, |  | ||||||
| 			status, |  | ||||||
| 			fee, |  | ||||||
| 			[[category, categoryId, quantity]], |  | ||||||
| 		]) => ({ |  | ||||||
| 			serialNum: sn, |  | ||||||
| 			createdAt: time, |  | ||||||
| 			giverAid: giver[0], |  | ||||||
| 			giverName: giver[1], |  | ||||||
| 			isGiver: giver[0] === playerAid, |  | ||||||
| 			receiverAid: receiver[0], |  | ||||||
| 			receiverName: receiver[1], |  | ||||||
| 			status: +status, |  | ||||||
| 			quantity, |  | ||||||
| 			fee, |  | ||||||
| 		}), |  | ||||||
| 	); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function calculatedReward(rewards: [number, number][]) { |  | ||||||
| 	const maximum = 6; |  | ||||||
| 	const result = []; |  | ||||||
| 	const couponType = ResourceItemType.Card_Coupon; |  | ||||||
| 	rewards.forEach(([type, quantity]) => { |  | ||||||
| 		if (type === couponType && quantity > maximum) { |  | ||||||
| 			const packNum = Math.floor(quantity / maximum); |  | ||||||
| 			const returnPack = Array.from({ length: packNum }, () => [ |  | ||||||
| 				couponType, |  | ||||||
| 				maximum, |  | ||||||
| 			]); |  | ||||||
| 			const remainder = quantity % maximum; |  | ||||||
| 			const returnRemainder = remainder ? [couponType, remainder] : null; |  | ||||||
| 			if (returnRemainder) { |  | ||||||
| 				returnPack.push(returnRemainder); |  | ||||||
| 			} |  | ||||||
| 			returnPack.forEach((item) => result.push(item)); |  | ||||||
| 		} else { |  | ||||||
| 			result.push([type, quantity]); |  | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const random = (min: number, max: number) => |  | ||||||
| 	Math.floor(Math.random() * (max - min)) + min; |  | ||||||
|  |  | ||||||
| // Default color is a bright yellow |  | ||||||
| const DEFAULT_COLOR = "hsl(50deg, 100%, 50%)"; |  | ||||||
| export const generateSparkle = (color = DEFAULT_COLOR) => { |  | ||||||
| 	return { |  | ||||||
| 		id: "" + random(10000, 99999), |  | ||||||
| 		createdAt: Date.now(), |  | ||||||
| 		// Bright yellow color: |  | ||||||
| 		color, |  | ||||||
| 		size: random(20, 60), |  | ||||||
| 		style: { |  | ||||||
| 			// Pick a random spot in the available space |  | ||||||
| 			top: random(0, 100) + "%", |  | ||||||
| 			left: random(0, 100) + "%", |  | ||||||
| 			// Float sparkles above sibling content |  | ||||||
| 			zIndex: 2, |  | ||||||
| 		}, |  | ||||||
| 	}; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export const range = (start, end, step = 1) => { |  | ||||||
| 	const output = []; |  | ||||||
| 	if (typeof end === "undefined") { |  | ||||||
| 		end = start; |  | ||||||
| 		start = 0; |  | ||||||
| 	} |  | ||||||
| 	for (let i = start; i < end; i += step) { |  | ||||||
| 		output.push(i); |  | ||||||
| 	} |  | ||||||
| 	return output; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export async function waitSetBusinessType() { |  | ||||||
| 	while (!BusinessTypeSetting.UseHost) { |  | ||||||
| 		await sleep(100); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 是否為好友 |  | ||||||
|  * @param {number} aId AID |  | ||||||
|  */ |  | ||||||
| export function isMyFriend(aId: number): boolean { |  | ||||||
| 	let isTrue: boolean = false; |  | ||||||
| 	const playerData = Player.data.getState(); |  | ||||||
| 	const lists: FriendRequest.ListFriendData = playerData.account.allowList; |  | ||||||
| 	for (let i = 0; i < lists.length; i++) { |  | ||||||
| 		const list: FriendRequest.SingleFriendData = lists[i]; |  | ||||||
| 		if (list[0] === aId) { |  | ||||||
| 			isTrue = true; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return isTrue; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 是否為黑單 |  | ||||||
|  * @param {number} aId AID |  | ||||||
|  */ |  | ||||||
| export function isMyDeny(aId: number): boolean { |  | ||||||
| 	let isTrue: boolean = false; |  | ||||||
| 	const playerData = Player.data.getState(); |  | ||||||
| 	const lists: FriendRequest.ListFriendData = playerData.account.denyList; |  | ||||||
| 	for (let i = 0; i < lists.length; i++) { |  | ||||||
| 		const list: FriendRequest.SingleFriendData = lists[i]; |  | ||||||
| 		if (list[0] === aId) { |  | ||||||
| 			isTrue = true; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return isTrue; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export const sheetNameResourceTypeSwitcher = ( |  | ||||||
| 	resourceType: ResourceItemType, |  | ||||||
| ) => { |  | ||||||
| 	switch (resourceType) { |  | ||||||
| 		case ResourceItemType.Card_Coupon: |  | ||||||
| 			return "CouponSetting"; |  | ||||||
| 		case ResourceItemType.Card: |  | ||||||
| 			return "Card1Setting"; |  | ||||||
| 		default: |  | ||||||
| 			return "Card1Setting"; |  | ||||||
| 	} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| export function escapeCodesNToBr(v: string): string { |  | ||||||
| 	return v.replace(/\n/g, "<br>"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 切割顯示字串長度 |  | ||||||
|  * @param str |  | ||||||
|  * @param showBytes 字元數(1中文2BYTES) |  | ||||||
|  * @returns |  | ||||||
|  */ |  | ||||||
| export function trimString( |  | ||||||
| 	str: string, |  | ||||||
| 	showBytes: number = 12, |  | ||||||
| 	ellipses: boolean = true, |  | ||||||
| ): string { |  | ||||||
| 	if (!str) { |  | ||||||
| 		return str; |  | ||||||
| 	} |  | ||||||
| 	let bytes: number = stringWidth(str); |  | ||||||
| 	if (bytes <= showBytes) { |  | ||||||
| 		return str; |  | ||||||
| 	} |  | ||||||
| 	let byteAmount: number = 0; |  | ||||||
| 	let strLength: number = str.length; |  | ||||||
| 	for (let i: number = 0; i < strLength; i++) { |  | ||||||
| 		let word: string = str[i]; |  | ||||||
| 		bytes = stringWidth(word); |  | ||||||
| 		byteAmount += bytes; |  | ||||||
| 		if (byteAmount > showBytes) { |  | ||||||
| 			let checkStr: string = str.substring(0, i + 1); |  | ||||||
| 			let checkByte: number = stringWidth(checkStr); |  | ||||||
| 			if (checkByte < showBytes) { |  | ||||||
| 				byteAmount = checkByte; |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 			let result: string = str.substring(0, i); |  | ||||||
| 			if (ellipses) { |  | ||||||
| 				return result + "..."; |  | ||||||
| 			} else { |  | ||||||
| 				return result; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	console.error("Trim Nickname Error."); |  | ||||||
| 	return str; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** CommonEventType */ |  | ||||||
| export enum CommonEventType { |  | ||||||
| 	/** Maintenance */ |  | ||||||
| 	Maintenance, |  | ||||||
| 	/**ActivityReRender */ |  | ||||||
| 	ActivityReRender, |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| export function responsiveText(characters: number): number { |  | ||||||
| 	if (characters <= 10) return 1.125; |  | ||||||
| 	if (characters > 10 && characters <= 20) return 0.9; |  | ||||||
| 	if (characters > 20) return 0.8; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function discount(numberOff: number): number { |  | ||||||
| 	return (100 - numberOff) / 100; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** 預載字體 */ |  | ||||||
| export function PreloadFont(fonts: string[]): void { |  | ||||||
| 	// Check if API exists |  | ||||||
| 	if (document && document.fonts) { |  | ||||||
| 		// Do not block page loading |  | ||||||
| 		setTimeout(function (): void { |  | ||||||
| 			let successCount: number = 0; |  | ||||||
| 			for (let i: number = 0; i < fonts.length; i++) { |  | ||||||
| 				const font: string = fonts[i]; |  | ||||||
| 				// eslint-disable-next-line no-loop-func |  | ||||||
| 				document.fonts.load(`16px ${font}`).then(() => { |  | ||||||
| 					// Make font using elements visible |  | ||||||
| 					successCount++; |  | ||||||
| 					if (successCount === fonts.length) { |  | ||||||
| 						document.documentElement.classList.add("font-loaded"); |  | ||||||
| 					} |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
| 		}, 0); |  | ||||||
| 	} else { |  | ||||||
| 		// Fallback if API does not exist |  | ||||||
| 		document.documentElement.classList.add("font-loaded"); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // PWA |  | ||||||
| /** BeforeInstallPromptEvent */ |  | ||||||
| export let deferredPrompt: any; |  | ||||||
| window.addEventListener("beforeinstallprompt", (e) => { |  | ||||||
| 	// Prevent Chrome 67 and earlier from automatically showing the prompt |  | ||||||
| 	e.preventDefault(); |  | ||||||
| 	// Stash the event so it can be triggered later. |  | ||||||
| 	deferredPrompt = e; |  | ||||||
| 	// Update UI to notify the user they can add to home screen |  | ||||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, e); |  | ||||||
| }); |  | ||||||
| export function addToHomeScreen(): void { |  | ||||||
| 	if (isMobile) { |  | ||||||
| 		let url: string = |  | ||||||
| 			BusinessTypeSetting.UsePatch + |  | ||||||
| 			"addtohomescreen/index.html" + |  | ||||||
| 			"?v=" + |  | ||||||
| 			Date.now(); |  | ||||||
| 		liff.openWindow({ |  | ||||||
| 			url: url, |  | ||||||
| 			external: true, |  | ||||||
| 		}); |  | ||||||
| 	} else { |  | ||||||
| 		if (deferredPrompt) { |  | ||||||
| 			// Show the prompt |  | ||||||
| 			deferredPrompt.prompt(); |  | ||||||
| 			// Wait for the user to respond to the prompt |  | ||||||
| 			deferredPrompt.userChoice.then((choiceResult) => { |  | ||||||
| 				if (choiceResult.outcome === "accepted") { |  | ||||||
| 					// console.log("User accepted the A2HS prompt"); |  | ||||||
| 					Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, false); |  | ||||||
| 				} else { |  | ||||||
| 					// console.log("User dismissed the A2HS prompt"); |  | ||||||
| 				} |  | ||||||
| 				deferredPrompt = null; |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getArray(count: number): number[] { |  | ||||||
| 	const array: number[] = []; |  | ||||||
| 	for (let i: number = 0; i < count; i++) { |  | ||||||
| 		array.push(i); |  | ||||||
| 	} |  | ||||||
| 	return array; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** 判斷登入並且Line綁定完 */ |  | ||||||
| export function checkWait(): boolean { |  | ||||||
| 	const playerData = Player.data.getState(); |  | ||||||
| 	const isLineBind: boolean = Player.hasUserBindFlag(UserBindFlag.LineBind); |  | ||||||
| 	if (!BaseEnumerator.isInit) { |  | ||||||
| 		return true; |  | ||||||
| 	} else if (!CocosVueScript.Instance || !CocosVueScript.Instance?.GetLoginData()) { |  | ||||||
| 		return true; |  | ||||||
| 	} else if (!playerData.account.role && !isLineBind) { |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function scrollToBottom(dynamicListHeight: number, duration: number = 200) { |  | ||||||
| 	Scroll.animateScroll.scrollTo(dynamicListHeight, { |  | ||||||
| 		duration: duration, |  | ||||||
| 		smooth: "easeInQuad", |  | ||||||
| 		containerId: "scrollableDiv", |  | ||||||
| 		offset: 50 |  | ||||||
| 	}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function Copy(serialNum: string) { |  | ||||||
| 	try { |  | ||||||
| 		navigator.clipboard.writeText(serialNum); |  | ||||||
| 	} |  | ||||||
| 	catch (error) { |  | ||||||
| 		console.error(error); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,235 +1,26 @@ | |||||||
| import MainControl from "@/Common/MainControl/MainControl"; | import CSMessage from "@/Common/Message/CSMessage"; | ||||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||||
| import { TTeamBattleData } from "@/UI/RouterPage/GameContent/GameContentUtils"; |  | ||||||
| import { Cocos } from "@/assets/VueScript/Cocos"; |  | ||||||
| import { CommonEventCallBack } from "@/assets/VueScript/CocosVueScript"; |  | ||||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; |  | ||||||
| import { GiftCallBack, GiftEventEnum, PanelType, UpdateOneListInfo } from "@/components/ModalContent/TxnModal/txnUtils"; |  | ||||||
| import { gameObj } from "@/context/GameItemsContext"; | import { gameObj } from "@/context/GameItemsContext"; | ||||||
| import { LocalStorage } from "@/define"; | import { GameInfoRequest } from "@/define/Request/GameRequest"; | ||||||
| import { EActivitySyncType, RpcActivityComSyncResponse, TActivityComSyncData, TActivitySyncData } from "@/define/Request/ActivityRequest"; |  | ||||||
| import { ResponseBackpackInfo } from "@/define/Request/BackpackRequest"; |  | ||||||
| import { FriendRequest } from "@/define/Request/FriendRequest"; |  | ||||||
| import { ProfileRequest } from "@/define/Request/ProfileRequest"; |  | ||||||
| import { TxnRequest } from "@/define/Request/TxnRequest"; |  | ||||||
| import { VipRequest } from "@/define/Request/VIPRequest"; |  | ||||||
| import Player from "@/modules/player"; |  | ||||||
| import { State } from "@/modules/player/define/data"; |  | ||||||
| import { BackpackItemData } from "@/modules/player/define/data/backpack"; |  | ||||||
| import { CommonEventType } from "."; |  | ||||||
|  |  | ||||||
| let SN: number = 0; | export function* gameSync(): IterableIterator<any> { | ||||||
|  | 	const { gameData, setGameData } = gameObj; | ||||||
| export function profileInfo(data: ProfileRequest.InfoResponse): void { | 	let req: GameInfoRequest = new GameInfoRequest(); | ||||||
| 	const playerData: State = Player.data.getState(); | 	yield req.SendAsync(); | ||||||
| 	if (data.aId !== playerData.account.aId) { | 	let resp: INetResponse<JSON> = req.Result; | ||||||
|  | 	/** 0是UUID 1[0]是機台相關資訊 1[1]排序 */ | ||||||
|  | 	if (resp.IsValid) { | ||||||
|  | 		const respD: any = resp.Data; | ||||||
|  | 	} else { | ||||||
|  | 		CSMessage.NetError(resp.Method, resp.Status, "Get GameInfoRequest Error"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	playerData.account.name = data.name; | 	const data: any = JSON.parse(resp.Data[1]); | ||||||
| 	playerData.account.message = data.msg; | 	const slotData = data[0]; | ||||||
| 	playerData.account.phone = data.phone; | 	const slotList: number[] = data[1][0]; | ||||||
| 	playerData.account.money = data.money; | 	setGameData({ | ||||||
| 	playerData.vip.level = data.vip; | 		...gameData, | ||||||
| 	Player.data.setState(playerData); | 		slotData, | ||||||
| } | 		slotList | ||||||
|  | 	}); | ||||||
| export function vipInfo(data: VipRequest.InfoResponse): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	playerData.vip.level = data.level; |  | ||||||
| 	playerData.vip.totalBet = data.bet; |  | ||||||
| 	playerData.vip.totalCharge = data.sv; |  | ||||||
| 	playerData.vip.rich = data.rich; |  | ||||||
| 	playerData.vip.et = data.et; |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function friendAllowList(data: FriendRequest.ListFriendData): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	playerData.account.allowList = data; |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function friendDenyList(data: FriendRequest.ListFriendData): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	playerData.account.denyList = data; |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function activityComSync(data: RpcActivityComSyncResponse): void { |  | ||||||
| 	const { teamBattleData, setTeamBattleData } = gameObj; |  | ||||||
| 	for (let i = 0; i < data.length; i++) { |  | ||||||
| 		const activityComSyncData: TActivityComSyncData = data[i]; |  | ||||||
| 		const [id, activitySyncDatas] = activityComSyncData; |  | ||||||
| 		// for (let j = 0; j < teamBattleData.length; j++) { |  | ||||||
| 		// 	const teamBattle: TTeamBattleData = teamBattleData[j]; |  | ||||||
| 		// 	const [teamBattleId, , ,] = teamBattle; |  | ||||||
| 		// 	if (id === teamBattleId) { |  | ||||||
| 		// 		for (let k = 0; k < activitySyncDatas.length; k++) { |  | ||||||
| 		// 			const activitySyncData: TActivitySyncData = activitySyncDatas[k]; |  | ||||||
| 		// 			const [type, value] = activitySyncData; |  | ||||||
| 		// 			switch (type) { |  | ||||||
| 		// 				case EActivitySyncType.IsOpen: { |  | ||||||
| 		// 					teamBattleData[j][1] = -1; |  | ||||||
| 		// 					setTeamBattleData(teamBattleData); |  | ||||||
| 		// 					break; |  | ||||||
| 		// 				} |  | ||||||
|  |  | ||||||
| 		// 				case EActivitySyncType.Sync: { |  | ||||||
| 		// 					teamBattleData[j][1] = value; |  | ||||||
| 		// 					setTeamBattleData(teamBattleData); |  | ||||||
| 		// 					break; |  | ||||||
| 		// 				} |  | ||||||
|  |  | ||||||
| 		// 				case EActivitySyncType.Task: { |  | ||||||
|  |  | ||||||
| 		// 					break; |  | ||||||
| 		// 				} |  | ||||||
|  |  | ||||||
| 		// 				default: |  | ||||||
| 		// 					break; |  | ||||||
| 		// 			} |  | ||||||
| 		// 		} |  | ||||||
| 		// 		break; |  | ||||||
| 		// 	} |  | ||||||
| 		// } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		for (let j = 0; j < activitySyncDatas.length; j++) { |  | ||||||
| 			const activitySyncData: TActivitySyncData = activitySyncDatas[j]; |  | ||||||
| 			const [type, value] = activitySyncData; |  | ||||||
| 			switch (type) { |  | ||||||
| 				case EActivitySyncType.IsOpen: { |  | ||||||
| 					// for (let k = 0; k < teamBattleData.length; k++) { |  | ||||||
| 					// 	const teamBattle: TTeamBattleData = teamBattleData[k]; |  | ||||||
| 					// 	const [teamBattleId, , ,] = teamBattle; |  | ||||||
| 					// 	if (id === teamBattleId) { |  | ||||||
| 					// 		teamBattleData[j][1] = value; |  | ||||||
| 					// 		setTeamBattleData(teamBattleData); |  | ||||||
| 					// 		break; |  | ||||||
| 					// 	} |  | ||||||
| 					// } |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				case EActivitySyncType.Sync: { |  | ||||||
| 					for (let k = 0; k < teamBattleData.length; k++) { |  | ||||||
| 						const teamBattle: TTeamBattleData = teamBattleData[k]; |  | ||||||
| 						const [teamBattleId, , ,] = teamBattle; |  | ||||||
| 						if (id === teamBattleId) { |  | ||||||
| 							teamBattleData[j][1] = value; |  | ||||||
| 							setTeamBattleData(teamBattleData); |  | ||||||
| 							break; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				case EActivitySyncType.Task: { |  | ||||||
|  |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				default: |  | ||||||
| 					break; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	CommonEventCallBack.DispatchCallback(CommonEventType.ActivityReRender, null); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function backpackInfo(data: ResponseBackpackInfo[], isAdd: boolean = false): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	const backpackList: BackpackItemData[] = isAdd ? playerData.backpack.Copy() : []; |  | ||||||
| 	for (let i = 0; i < data.length; i++) { |  | ||||||
| 		const backpackServerData = data[i]; |  | ||||||
| 		const id: number = backpackServerData[1][0]; |  | ||||||
| 		const count: number = backpackServerData[1][1]; |  | ||||||
| 		for (let j = 0; j < count; j++) { |  | ||||||
| 			const backpackClientData: BackpackItemData = { |  | ||||||
| 				SN: SN, |  | ||||||
| 				ResourceType: backpackServerData[0], |  | ||||||
| 				ID: id, |  | ||||||
| 				Viewed: false, |  | ||||||
| 			}; |  | ||||||
| 			backpackList.push(backpackClientData); |  | ||||||
| 			SN++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if (!isAdd) { |  | ||||||
| 		const oldBackpackListStr: string = localStorage.getItem(LocalStorage.Key.Backpack); |  | ||||||
| 		if (oldBackpackListStr) { |  | ||||||
| 			const oldBackpackList: BackpackItemData[] = JSON.parse(oldBackpackListStr); |  | ||||||
| 			for (let i = 0; i < backpackList.length; i++) { |  | ||||||
| 				const backpack: BackpackItemData = backpackList[i]; |  | ||||||
| 				for (let j = 0; j < oldBackpackList.length; j++) { |  | ||||||
| 					const oldBackpack: BackpackItemData = oldBackpackList[j]; |  | ||||||
| 					if (backpack.ID === oldBackpack.ID && backpack.ResourceType === oldBackpack.ResourceType) { |  | ||||||
| 						backpackList[i].Viewed = oldBackpack.Viewed; |  | ||||||
| 						oldBackpackList.splice(j, 1); |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	playerData.backpack = backpackList; |  | ||||||
| 	localStorage.setItem(LocalStorage.Key.Backpack, JSON.stringify(playerData.backpack)); |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
|  |  | ||||||
| 	const totalUnreadCount: number = playerData.backpack.filter((item) => !item.Viewed).length; |  | ||||||
| 	if (!MainControl.Instance.IsInGame) { |  | ||||||
| 		Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetBackpackUnreadCount, totalUnreadCount); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function txnNew(data: TxnRequest.TxnInfo): void { |  | ||||||
| 	const playerData = Player.data.getState(); |  | ||||||
| 	const centerList = playerData.txn.centerList.slice(); |  | ||||||
| 	centerList.push(data); |  | ||||||
| 	playerData.txn.centerList = centerList; |  | ||||||
| 	GiftCallBack.DispatchCallback(GiftEventEnum.ReFlash, null); |  | ||||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetTxnUnreadCount, playerData.txn.centerList.length); |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function txnCenter(data: TxnRequest.TxnInfo[]): void { |  | ||||||
| 	const playerData = Player.data.getState(); |  | ||||||
| 	playerData.txn.centerList = data; |  | ||||||
| 	GiftCallBack.DispatchCallback(GiftEventEnum.ReFlash, null); |  | ||||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetTxnUnreadCount, playerData.txn.centerList.length); |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function txnTrade(data: TxnRequest.TradeResponse): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	const centerList: TxnRequest.TxnInfo[] = playerData.txn.centerList; |  | ||||||
| 	let type: number = PanelType.RecordPanel; |  | ||||||
| 	let status: number = +data.s; |  | ||||||
| 	if (status < 20) { |  | ||||||
| 		type = PanelType.CenterPanel; |  | ||||||
| 		switch (status) { |  | ||||||
| 			case 11: |  | ||||||
| 			case 12: |  | ||||||
| 			case 13: { |  | ||||||
| 				for (let i: number = 0; i < centerList.length; i++) { |  | ||||||
| 					const centerData: TxnRequest.TxnInfo = centerList[i]; |  | ||||||
| 					if (centerData[0] == +data.id && centerData[3][0] == playerData.account.aId) { |  | ||||||
| 						type = PanelType.RecordPanel; |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			default: |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	CoroutineV2.Single(UpdateOneListInfo(data.id, type)).Start(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function txnUserAdd(data: TxnRequest.UserAddResponse): void { |  | ||||||
| 	const playerData: State = Player.data.getState(); |  | ||||||
| 	playerData.txn.receiverList.push(data.u); |  | ||||||
| 	Player.data.setState(playerData); |  | ||||||
| } | } | ||||||
| @@ -13,7 +13,7 @@ | |||||||
| 		"allowSyntheticDefaultImports": true, | 		"allowSyntheticDefaultImports": true, | ||||||
| 		"strict": false, | 		"strict": false, | ||||||
| 		"strictNullChecks": false, | 		"strictNullChecks": false, | ||||||
| 		"forceConsistentCasingInFileNames": true, | 		"forceConsistentCasingInFileNames": false, | ||||||
| 		"noFallthroughCasesInSwitch": true, | 		"noFallthroughCasesInSwitch": true, | ||||||
| 		"module": "esnext", | 		"module": "esnext", | ||||||
| 		"moduleResolution": "node", | 		"moduleResolution": "node", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user