drgame-cc 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,15 +45,15 @@
45
45
  <body>
46
46
  <canvas id="GameCanvas" oncontextmenu="event.preventDefault()" tabindex="-1" style="outline: none;"></canvas>
47
47
  <div id="splash">
48
- <!-- <img id="logo" src="logo.png" alt="Logo"> -->
48
+ <img id="logo" src="logo.png" alt="Logo">
49
49
  <div id="splash-info">首次加载时间较长,请耐心等待</div>
50
50
  <div id="progress-status">正在启动引擎...0%</div>
51
51
  <div class="progress-bar">
52
52
  <span style="width: 0%"></span>
53
53
  </div>
54
54
 
55
- <div id="icp">备案号:豫ICP备18029698号-5A</div>
56
- <img id="age-rating" src="16+.png" alt="16+">
55
+ <!-- <div id="icp">备案号:豫ICP备18029698号-5A</div> -->
56
+ <!-- <img id="age-rating" src="16+.png" alt="16+"> -->
57
57
  </div>
58
58
  <script src="src/settings.js" charset="utf-8"></script>
59
59
  <script src="vconsole.min.js"></script>
Binary file
@@ -2,7 +2,9 @@ html {
2
2
  -ms-touch-action: none;
3
3
  }
4
4
 
5
- body, canvas, div {
5
+ body,
6
+ canvas,
7
+ div {
6
8
  display: block;
7
9
  outline: none;
8
10
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
@@ -18,9 +20,10 @@ body, canvas, div {
18
20
  /* Remove spin of input type number */
19
21
  input::-webkit-outer-spin-button,
20
22
  input::-webkit-inner-spin-button {
21
- /* display: none; <- Crashes Chrome on hover */
22
- -webkit-appearance: none;
23
- margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
23
+ /* display: none; <- Crashes Chrome on hover */
24
+ -webkit-appearance: none;
25
+ margin: 0;
26
+ /* <-- Apparently some margin are still there even though it's hidden */
24
27
  }
25
28
 
26
29
  body {
@@ -42,7 +45,7 @@ body {
42
45
 
43
46
  display: flex;
44
47
  flex-direction: column;
45
-
48
+
46
49
  /* fix bug: https://github.com/cocos-creator/2d-tasks/issues/791 */
47
50
  /* overflow cannot be applied in Cocos2dGameContainer,
48
51
  otherwise child elements will be hidden when Cocos2dGameContainer rotated 90 deg */
@@ -65,11 +68,13 @@ canvas {
65
68
  background-color: rgba(0, 0, 0, 0);
66
69
  }
67
70
 
68
- a:link, a:visited {
71
+ a:link,
72
+ a:visited {
69
73
  color: #666;
70
74
  }
71
75
 
72
- a:active, a:hover {
76
+ a:active,
77
+ a:hover {
73
78
  color: #666;
74
79
  }
75
80
 
@@ -87,101 +92,108 @@ p.footer {
87
92
  left: 0;
88
93
  width: 100%;
89
94
  height: 100%;
90
- background: #171717 url(./bg1.jpg) no-repeat center center;
95
+ background: #171717 url(./bg.png) no-repeat center center;
91
96
  /* 固定 splash.png 大小为 300x300 并保持居中 */
92
97
  background-size: cover;
93
-
98
+
94
99
  }
95
100
 
96
101
  .progress-bar {
97
- position: absolute;
98
- left: 50%;
99
- width: 40%;
100
- height: 12px;
101
- bottom: 13%;
102
- transform: translateX(-50%);
103
- border-radius: 3px;
104
- /*margin: 0 -175px;
102
+ position: absolute;
103
+ left: 50%;
104
+ width: 40%;
105
+ height: 12px;
106
+ bottom: 13%;
107
+ transform: translateX(-50%);
108
+ border-radius: 3px;
109
+ /*margin: 0 -175px;
105
110
  padding: 5px;
106
111
  box-shadow: 0 1px 5px rgba(0, 0, 0, .6) inset, 0 1px 0 rgba(255, 255, .2);*/
107
- background: url("jz-jdt-4.png") no-repeat center center;
108
- background-size: 100% 100%;
112
+ background: url("jz-jdt-4.png") no-repeat center center;
113
+ background-size: 100% 100%;
109
114
  }
110
115
 
111
116
  .progress-bar span {
112
- display: block;
113
- height: 100%;
114
- width: 0%;
115
- border-radius: 3px;
116
- /*box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;*/
117
- transition: width .4s ease-in-out;
118
- background: url("jz-jdt-3.png") no-repeat center center;
119
- background-size: 100% 100%;
117
+ display: block;
118
+ height: 100%;
119
+ width: 0%;
120
+ border-radius: 3px;
121
+ /*box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;*/
122
+ transition: width .4s ease-in-out;
123
+ background: url("jz-jdt-3.png") no-repeat center center;
124
+ background-size: 100% 100%;
120
125
  }
121
126
 
122
127
  #splash-info {
123
- position: absolute;
124
- left: 50%;
125
- bottom: 16%;
126
- transform: translateX(-50%);
127
- color: #fdecc8;
128
- font-size: clamp(12px, 1.5vw, 20px);
129
- z-index: 1000;
130
-
128
+ position: absolute;
129
+ left: 50%;
130
+ bottom: 16%;
131
+ transform: translateX(-50%);
132
+ color: #fdecc8;
133
+ font-size: clamp(12px, 1.5vw, 20px);
134
+ z-index: 1000;
135
+
131
136
  }
132
137
 
133
138
  #logo {
134
- position: absolute;
135
- top: 10px;
136
- left: 20px;
137
- z-index: 1000;
138
- max-width: 46vw;
139
- max-height: 24vh;
140
- width: auto;
141
- height: auto;
139
+ position: absolute;
140
+ left: 50%;
141
+ top: 40%;
142
+ transform: translate(-50%, -50%);
143
+ z-index: 1000;
144
+ max-width: 46vw;
145
+ max-height: 24vh;
146
+ width: auto;
147
+ height: auto;
142
148
  }
143
149
 
144
150
  #progress-status {
145
- position: absolute;
146
- left: 50%;
147
- bottom: 9%;
148
- transform: translateX(-50%);
149
- color: #fdecc8;
150
- font-size: clamp(12px, 1.5vw, 20px);
151
- z-index: 1000;
152
-
151
+ position: absolute;
152
+ left: 50%;
153
+ bottom: 9%;
154
+ transform: translateX(-50%);
155
+ color: #fdecc8;
156
+ font-size: clamp(12px, 1.5vw, 20px);
157
+ z-index: 1000;
158
+
153
159
  }
154
160
 
155
161
 
156
162
  .stripes span {
157
- background-size: 30px 30px;
158
- background-image: linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
159
- transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
160
- transparent 75%, transparent);
161
-
162
- animation: animate-stripes 1s linear infinite;
163
+ background-size: 30px 30px;
164
+ background-image: linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
165
+ transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
166
+ transparent 75%, transparent);
167
+
168
+ animation: animate-stripes 1s linear infinite;
163
169
  }
164
170
 
165
171
  @keyframes animate-stripes {
166
- 0% {background-position: 0 0;} 100% {background-position: 60px 0;}
172
+ 0% {
173
+ background-position: 0 0;
174
+ }
175
+
176
+ 100% {
177
+ background-position: 60px 0;
178
+ }
167
179
  }
168
180
 
169
181
  #icp {
170
- position: absolute;
171
- bottom: 2%;
172
- left: 50%;
173
- transform: translateX(-50%);
174
- color: #ef6e28;
175
- z-index: 1000;
176
- font-size: clamp(10px, 1.5vw, 18px);
177
-
182
+ position: absolute;
183
+ bottom: 2%;
184
+ left: 50%;
185
+ transform: translateX(-50%);
186
+ color: #ef6e28;
187
+ z-index: 1000;
188
+ font-size: clamp(10px, 1.5vw, 18px);
189
+
178
190
  }
179
191
 
180
192
  #age-rating {
181
- position: absolute;
182
- top: 50px;
183
- left: 50px;
184
- z-index: 1000;
185
- height: clamp(32px, 4vw, 56px);
186
- width: auto;
187
- }
193
+ position: absolute;
194
+ top: 50px;
195
+ left: 50px;
196
+ z-index: 1000;
197
+ height: clamp(32px, 4vw, 56px);
198
+ width: auto;
199
+ }
@@ -153,6 +153,7 @@ export class PlatformAdapter {
153
153
 
154
154
  /** 刷新界面按钮事件, 用于界面按钮变化(列表,下拉)后,需要刷新按钮事件 */
155
155
  public static refreshWindow(window: cc.Node) {
156
+ cc.Node.EventType.TOUCH_START
156
157
  TvUi.focus.registerButtons(window);
157
158
  }
158
159
 
@@ -162,4 +163,14 @@ export class PlatformAdapter {
162
163
  exitWin.parent = cc.director.getScene();
163
164
  exitWin.setPosition(cc.v2(cc.winSize.width / 2, cc.winSize.height / 2));
164
165
  }
166
+
167
+ /** 设置启动页进度条 */
168
+ public static setProgress(progress: number, tip: string) {
169
+ if (window["setProgress"]) window["setProgress"](progress, tip);
170
+ }
171
+
172
+ /** 关闭启动页 */
173
+ public static closeLoading() {
174
+ if (window["closeLoading"]) window["closeLoading"]();
175
+ }
165
176
  }
@@ -450,16 +450,16 @@ export default class FocusManager {
450
450
 
451
451
  private static invokeButton(button: cc.Button) {
452
452
  if (!button || !button.node || !button.node.activeInHierarchy || !button.interactable) return;
453
+ var event = new cc.Event.EventCustom(cc.Node.EventType.TOUCH_END, true);
454
+ event.target = button.node;
453
455
  if (button.clickEvents && button.clickEvents.length > 0) {
454
- cc.Component.EventHandler.emitEvents(button.clickEvents, null);
455
-
456
- var event = new cc.Event.EventCustom(cc.Node.EventType.TOUCH_END, true);
457
- button.node.emit(cc.Node.EventType.TOUCH_END, event);
458
- } else {
459
- // 模拟一个touch end事件
460
- var event = new cc.Event.EventCustom(cc.Node.EventType.TOUCH_END, true);
461
- button.node.emit(cc.Node.EventType.TOUCH_END, event);
456
+ cc.Component.EventHandler.emitEvents(button.clickEvents, event);
457
+ }
458
+ if (button instanceof cc.Toggle) {
459
+ button.isChecked = !button.isChecked;
460
+ cc.Component.EventHandler.emitEvents(button.checkEvents, event);
462
461
  }
462
+ button.node.emit(cc.Node.EventType.TOUCH_END, event);
463
463
  }
464
464
 
465
465
  private static emitFocusChanged(item: FocusRuntimeItem | null, previous?: FocusRuntimeItem | null) {
@@ -167,59 +167,59 @@ export default class FocusVisualLayer extends cc.Component {
167
167
  this.graphics.stroke();
168
168
  }
169
169
 
170
- private positionIcon(item: FocusRuntimeItem, iconConfig: TvUiIconItem) {
171
- if (!item || !item.node || !item.node.isValid) return;
172
- let focusConfig = TvUiConfigManager.getConfig().focus || {};
173
-
174
- let node = item.node;
175
- let worldPos = node.parent.convertToWorldSpaceAR(node.position);
176
- let local = this.node.convertToNodeSpaceAR(worldPos);
177
-
178
- let contentSize = node.getContentSize();
179
- let scaleX = node.scaleX;
180
- let scaleY = node.scaleY;
181
- let width = contentSize.width * scaleX;
182
- let height = contentSize.height * scaleY;
183
-
184
- let iconWidth = iconConfig.width || 60;
185
- let iconHeight = iconConfig.height || 60;
186
- let offsetX = iconConfig.offsetX;
187
- let offsetY = iconConfig.offsetY;
188
- if (offsetX === undefined) offsetX = focusConfig.iconOffsetX || 0;
189
- if (offsetY === undefined) offsetY = focusConfig.iconOffsetY || 0;
190
- if (!this.iconNode) return;
191
-
192
- let x = local.x + width / 2 + offsetX;
193
- let y = local.y + height / 2 + offsetY;
194
- if ((focusConfig.iconPlacement || "bottomRight") == "bottomRight") {
195
- y = local.y - height / 2 - offsetY;
196
- }
197
- this.iconNode.setContentSize(iconWidth, iconHeight);
198
- this.iconNode.setPosition(x, y);
199
- }
200
-
201
170
  // private positionIcon(item: FocusRuntimeItem, iconConfig: TvUiIconItem) {
202
171
  // if (!item || !item.node || !item.node.isValid) return;
203
172
  // let focusConfig = TvUiConfigManager.getConfig().focus || {};
204
- // let box = item.node.getBoundingBoxToWorld();
205
- // let center = cc.v2(box.x + box.width / 2, box.y + box.height / 2);
206
- // let local = this.node.convertToNodeSpaceAR(center);
207
- // let width = iconConfig.width || 60;
208
- // let height = iconConfig.height || 60;
173
+
174
+ // let node = item.node;
175
+ // let worldPos = node.parent.convertToWorldSpaceAR(node.position);
176
+ // let local = this.node.convertToNodeSpaceAR(worldPos);
177
+
178
+ // let contentSize = node.getContentSize();
179
+ // let scaleX = node.scaleX;
180
+ // let scaleY = node.scaleY;
181
+ // let width = contentSize.width * scaleX;
182
+ // let height = contentSize.height * scaleY;
183
+
184
+ // let iconWidth = iconConfig.width || 60;
185
+ // let iconHeight = iconConfig.height || 60;
209
186
  // let offsetX = iconConfig.offsetX;
210
187
  // let offsetY = iconConfig.offsetY;
211
188
  // if (offsetX === undefined) offsetX = focusConfig.iconOffsetX || 0;
212
189
  // if (offsetY === undefined) offsetY = focusConfig.iconOffsetY || 0;
213
190
  // if (!this.iconNode) return;
214
- // let x = local.x + box.width / 2 + offsetX;
215
- // let y = local.y + box.height / 2 + offsetY;
191
+
192
+ // let x = local.x + width / 2 + offsetX;
193
+ // let y = local.y + height / 2 + offsetY;
216
194
  // if ((focusConfig.iconPlacement || "bottomRight") == "bottomRight") {
217
- // y = local.y - box.height / 2 - offsetY;
195
+ // y = local.y - height / 2 - offsetY;
218
196
  // }
219
- // this.iconNode.setContentSize(width, height);
197
+ // this.iconNode.setContentSize(iconWidth, iconHeight);
220
198
  // this.iconNode.setPosition(x, y);
221
199
  // }
222
200
 
201
+ private positionIcon(item: FocusRuntimeItem, iconConfig: TvUiIconItem) {
202
+ if (!item || !item.node || !item.node.isValid) return;
203
+ let focusConfig = TvUiConfigManager.getConfig().focus || {};
204
+ let box = item.node.getBoundingBoxToWorld();
205
+ let center = cc.v2(box.x + box.width / 2, box.y + box.height / 2);
206
+ let local = this.node.convertToNodeSpaceAR(center);
207
+ let width = iconConfig.width || 60;
208
+ let height = iconConfig.height || 60;
209
+ let offsetX = iconConfig.offsetX;
210
+ let offsetY = iconConfig.offsetY;
211
+ if (offsetX === undefined) offsetX = focusConfig.iconOffsetX || 0;
212
+ if (offsetY === undefined) offsetY = focusConfig.iconOffsetY || 0;
213
+ if (!this.iconNode) return;
214
+ let x = local.x + box.width / 2 + offsetX;
215
+ let y = local.y + box.height / 2 + offsetY;
216
+ if ((focusConfig.iconPlacement || "bottomRight") == "bottomRight") {
217
+ y = local.y - box.height / 2 - offsetY;
218
+ }
219
+ this.iconNode.setContentSize(width, height);
220
+ this.iconNode.setPosition(x, y);
221
+ }
222
+
223
223
  private resizeToParent() {
224
224
  let parent = this.node.parent;
225
225
  let width = parent && parent.width ? parent.width : (cc.winSize && cc.winSize.width) || 1920;
@@ -0,0 +1,55 @@
1
+ import TvUi from "../core/TvUi";
2
+ import { TvRemoteKey } from "./KeyCodeAdapter";
3
+
4
+ const { ccclass, property } = cc._decorator;
5
+
6
+ @ccclass
7
+ export default class KeyboardMove extends cc.Component {
8
+ /**
9
+ * 按键移动回调
10
+ */
11
+ public callback: (dir: cc.Vec2) => void;
12
+ private _keys: Set<TvRemoteKey> = new Set();
13
+ private _dir: cc.Vec2 = cc.v2(0, 0);
14
+
15
+ onLoad(): void {
16
+ cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
17
+ cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
18
+ }
19
+
20
+ onDestroy(): void {
21
+ cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
22
+ cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
23
+ this._keys.clear();
24
+ }
25
+
26
+ private onKeyDown(event: cc.Event.EventKeyboard): void {
27
+ let key = TvUi.input.toRemoteKey(event.keyCode);
28
+ this._keys.add(key);
29
+ }
30
+
31
+ private onKeyUp(event: cc.Event.EventKeyboard): void {
32
+ let key = TvUi.input.toRemoteKey(event.keyCode);
33
+ this._keys.delete(key);
34
+ }
35
+
36
+ update(dt: number): void {
37
+ if (this._keys.size === 0)
38
+ return;
39
+
40
+ const dir = this._dir;
41
+ dir.x = 0;
42
+ dir.y = 0;
43
+
44
+ if (this._keys.has(TvRemoteKey.Left)) dir.x -= 1;
45
+ if (this._keys.has(TvRemoteKey.Right)) dir.x += 1;
46
+ if (this._keys.has(TvRemoteKey.Down)) dir.y -= 1;
47
+ if (this._keys.has(TvRemoteKey.Up)) dir.y += 1;
48
+
49
+ if (dir.x !== 0 || dir.y !== 0) {
50
+ dir.normalizeSelf();
51
+ }
52
+
53
+ if (this.callback) this.callback(dir);
54
+ }
55
+ }
@@ -0,0 +1,214 @@
1
+ export interface VirtualGamepadClientOptions {
2
+ wsUrl: string;
3
+ roomId: string;
4
+ deviceId: string;
5
+ game: string;
6
+ userId: string;
7
+ userType: "xiaomi" | "guest";
8
+ guestId?: string;
9
+ token?: string;
10
+ maxMembers: number;
11
+ }
12
+
13
+ export type VirtualGamepadConnectionState = "idle" | "connecting" | "open" | "joined" | "closed" | "error";
14
+
15
+ export default class VirtualGamepadClient {
16
+ private socket: WebSocket | null = null;
17
+ private options: VirtualGamepadClientOptions | null = null;
18
+ private manualClose: boolean = false;
19
+ private reconnectCount: number = 0;
20
+ private heartbeatTimer: any = -1;
21
+ private reconnectTimer: any = -1;
22
+ private readonly maxReconnectCount: number = 3;
23
+ private readonly heartbeatMs: number = 10000;
24
+
25
+ public onStateChange: ((state: VirtualGamepadConnectionState, reason?: string) => void) | null = null;
26
+ public onMessage: ((message: any) => void) | null = null;
27
+
28
+ public connect(options: VirtualGamepadClientOptions) {
29
+ this.options = options;
30
+ this.manualClose = false;
31
+ this.clearReconnect();
32
+ this.openSocket();
33
+ }
34
+
35
+ public close() {
36
+ this.manualClose = true;
37
+ this.clearHeartbeat();
38
+ this.clearReconnect();
39
+ if (this.socket) {
40
+ this.socket.onopen = null;
41
+ this.socket.onmessage = null;
42
+ this.socket.onclose = null;
43
+ this.socket.onerror = null;
44
+ try {
45
+ this.socket.close();
46
+ } catch (e) {
47
+ }
48
+ }
49
+ this.socket = null;
50
+ this.emitState("closed");
51
+ }
52
+
53
+ public send(message: any): boolean {
54
+ if (!this.socket || this.socket.readyState != WebSocket.OPEN) {
55
+ return false;
56
+ }
57
+ try {
58
+ this.socket.send(JSON.stringify(message));
59
+ return true;
60
+ } catch (e) {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ private openSocket() {
66
+ if (!this.options || !this.options.wsUrl) return;
67
+ this.clearHeartbeat();
68
+ this.emitState("connecting");
69
+ let options = this.options;
70
+ let query: { [key: string]: string } = {
71
+ roomId: options.roomId,
72
+ deviceId: options.deviceId,
73
+ role: "game",
74
+ userId: options.userId,
75
+ userType: options.userType,
76
+ maxMembers: String(options.maxMembers)
77
+ };
78
+ if (options.guestId) query.guestId = options.guestId;
79
+ if (options.token) query.token = options.token;
80
+ let url = this.appendParams(options.wsUrl, query);
81
+ try {
82
+ this.socket = new WebSocket(url);
83
+ this.socket.onopen = this.handleOpen.bind(this);
84
+ this.socket.onmessage = this.handleMessage.bind(this);
85
+ this.socket.onclose = this.handleClose.bind(this);
86
+ this.socket.onerror = this.handleError.bind(this);
87
+ } catch (e) {
88
+ this.handleError(e);
89
+ }
90
+ }
91
+
92
+ private handleOpen() {
93
+ if (!this.options) return;
94
+ this.reconnectCount = 0;
95
+ this.emitState("open");
96
+ let joinMessage: any = {
97
+ type: "join",
98
+ roomId: this.options.roomId,
99
+ role: "game",
100
+ deviceId: this.options.deviceId,
101
+ userId: this.options.userId,
102
+ userType: this.options.userType,
103
+ maxMembers: this.options.maxMembers,
104
+ game: this.options.game
105
+ };
106
+ if (this.options.guestId) joinMessage.guestId = this.options.guestId;
107
+ if (this.options.token) joinMessage.token = this.options.token;
108
+ console.log("[VirtualGamepad][WSS][Send] join", {
109
+ type: joinMessage.type,
110
+ roomId: joinMessage.roomId,
111
+ role: joinMessage.role,
112
+ deviceId: joinMessage.deviceId,
113
+ userId: joinMessage.userId,
114
+ userType: joinMessage.userType,
115
+ guestId: joinMessage.guestId || "",
116
+ maxMembers: joinMessage.maxMembers,
117
+ game: joinMessage.game,
118
+ hasToken: !!joinMessage.token
119
+ });
120
+ this.send(joinMessage);
121
+ this.startHeartbeat();
122
+ }
123
+
124
+ private handleMessage(event: MessageEvent) {
125
+ let data = event && event.data;
126
+ let message: any = null;
127
+ try {
128
+ message = typeof data == "string" ? JSON.parse(data) : data;
129
+ } catch (e) {
130
+ return;
131
+ }
132
+ if (!message) return;
133
+ if (message.type != "pong") {
134
+ console.log("[VirtualGamepad][WSS][Receive]", message);
135
+ }
136
+ if (message.type == "joined" || message.type == "welcome") {
137
+ this.emitState("joined");
138
+ }
139
+ if (this.onMessage) {
140
+ this.onMessage(message);
141
+ }
142
+ }
143
+
144
+ private handleClose(event?: any) {
145
+ this.clearHeartbeat();
146
+ this.socket = null;
147
+ this.emitState("closed", event && event.reason);
148
+ if (!this.manualClose) {
149
+ this.scheduleReconnect();
150
+ }
151
+ }
152
+
153
+ private handleError(event?: any) {
154
+ this.emitState("error", event && event.message);
155
+ if (!this.manualClose && (!this.socket || this.socket.readyState == WebSocket.CLOSED)) {
156
+ this.scheduleReconnect();
157
+ }
158
+ }
159
+
160
+ private startHeartbeat() {
161
+ this.clearHeartbeat();
162
+ this.heartbeatTimer = setInterval(() => {
163
+ if (!this.options) return;
164
+ this.send({
165
+ type: "ping",
166
+ roomId: this.options.roomId,
167
+ deviceId: this.options.deviceId,
168
+ role: "game",
169
+ timestamp: Date.now(),
170
+ ts: Date.now()
171
+ });
172
+ }, this.heartbeatMs);
173
+ }
174
+
175
+ private scheduleReconnect() {
176
+ if (this.reconnectCount >= this.maxReconnectCount) {
177
+ return;
178
+ }
179
+ this.clearReconnect();
180
+ this.reconnectCount++;
181
+ this.reconnectTimer = setTimeout(() => {
182
+ this.openSocket();
183
+ }, 1200 * this.reconnectCount);
184
+ }
185
+
186
+ private appendParams(url: string, params: { [key: string]: string }): string {
187
+ let query = [];
188
+ for (let key in params) {
189
+ query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key] || ""));
190
+ }
191
+ let separator = url.indexOf("?") >= 0 ? "&" : "?";
192
+ return url + separator + query.join("&");
193
+ }
194
+
195
+ private emitState(state: VirtualGamepadConnectionState, reason?: string) {
196
+ if (this.onStateChange) {
197
+ this.onStateChange(state, reason);
198
+ }
199
+ }
200
+
201
+ private clearHeartbeat() {
202
+ if (this.heartbeatTimer != -1) {
203
+ clearInterval(this.heartbeatTimer);
204
+ this.heartbeatTimer = -1;
205
+ }
206
+ }
207
+
208
+ private clearReconnect() {
209
+ if (this.reconnectTimer != -1) {
210
+ clearTimeout(this.reconnectTimer);
211
+ this.reconnectTimer = -1;
212
+ }
213
+ }
214
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "ver": "1.1.0",
3
+ "uuid": "dc301a42-a41d-4d44-bf7b-9f6bdde0230f",
4
+ "importer": "typescript",
5
+ "isPlugin": false,
6
+ "loadPluginInWeb": true,
7
+ "loadPluginInNative": true,
8
+ "loadPluginInEditor": false,
9
+ "subMetas": {}
10
+ }