dglabv3 0.1.dev6__py3-none-any.whl

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.
dglabv3/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .dglab import dglabv3
2
+ from .dtype import Channel,StrengthType
3
+ from .waves import PULSES, ALL_PULSES, Pulse
dglabv3/dglab.py ADDED
@@ -0,0 +1,340 @@
1
+ import websocket
2
+ import json
3
+ import logging
4
+ import qrcode
5
+ import threading
6
+ import io
7
+ from threading import Event
8
+ import asyncio
9
+ from dglabv3.dtype import (
10
+ Channel,
11
+ StrengthType,
12
+ StrengthMode,
13
+ MessageType,
14
+ ChannelStrength,
15
+ )
16
+
17
+ logging.basicConfig(level=logging.INFO)
18
+ logger = logging.getLogger("dglabv3")
19
+
20
+
21
+ class dglabv3:
22
+ def __init__(self) -> None:
23
+ self.client = None
24
+ self.clienturl = "wss://ws.dungeon-lab.cn/"
25
+ self.client_id = None
26
+ self.target_id = None
27
+ self.heartbeat_interval = None
28
+ self.pulse_name = None
29
+ self.clientqrurl = "https://www.dungeon-lab.com/app-download.php#DGLAB-SOCKET#wss://ws.dungeon-lab.cn/"
30
+ self.interval = 20
31
+ self.maxInterval = 50
32
+ self.strength = ChannelStrength()
33
+ self._bind_event = Event()
34
+ self._app_connect_event = Event()
35
+
36
+ def is_connected(self) -> bool:
37
+ return self.client and self.client.sock and self.client.sock.connected
38
+
39
+ def is_linked_to_app(self) -> bool:
40
+ return self.client_id is not None
41
+
42
+ async def connect_and_wait(self) -> None:
43
+ """連接並等待bind完成"""
44
+ self.connect()
45
+ await asyncio.get_event_loop().run_in_executor(None, self._bind_event.wait)
46
+
47
+ async def wait_for_app_connect(self) -> None:
48
+ """等待app連結"""
49
+ await asyncio.get_event_loop().run_in_executor(
50
+ None, self._app_connect_event.wait
51
+ )
52
+
53
+ def connect(self) -> None:
54
+ def on_message(ws, message):
55
+ self._handle_message(message)
56
+
57
+ def on_error(ws, error):
58
+ logger.error(f"WebSocket connection error: {error}")
59
+ self.close()
60
+
61
+ def on_close(ws, close_status_code, close_msg):
62
+ logger.info("WebSocket connection closed")
63
+ self._stop_heartbeat()
64
+
65
+ def on_open(ws):
66
+ logger.info("WebSocket connected")
67
+
68
+ self.client = websocket.WebSocketApp(
69
+ self.clienturl,
70
+ on_message=on_message,
71
+ on_error=on_error,
72
+ on_close=on_close,
73
+ on_open=on_open,
74
+ )
75
+
76
+ wst = threading.Thread(target=self.client.run_forever)
77
+ wst.daemon = True
78
+ wst.start()
79
+
80
+ def generate_qrcode(self) -> io.BytesIO:
81
+ if self.client_id is None:
82
+ logger.error("Client ID is empty, please connect to the server first")
83
+ return
84
+ qr = qrcode.QRCode()
85
+ qr.add_data(self.clientqrurl + self.client_id)
86
+ qr.make(fit=True)
87
+ img = qr.make_image(fill_color="black", back_color="white")
88
+ saveimg = io.BytesIO()
89
+ img.save(saveimg, format="PNG")
90
+ saveimg.seek(0)
91
+ return saveimg
92
+
93
+ def generate_qrcode_text(self) -> str:
94
+ print("im in")
95
+ if self.client_id is None:
96
+ logger.error("Client ID is empty, please connect to the server first")
97
+ return
98
+ qr = qrcode.QRCode()
99
+ qr.add_data(self.clientqrurl + self.client_id)
100
+ f = io.StringIO()
101
+ qr.print_ascii(out=f)
102
+ return f.getvalue()
103
+
104
+ def _update_connects(self, message: dict):
105
+ if message["targetId"] and message["targetId"] != "":
106
+ self.target_id = message["targetId"]
107
+ self.set_strength(Channel.A, StrengthType.SPECIFIC, self.strength.A)
108
+ self.set_strength(Channel.B, StrengthType.SPECIFIC, self.strength.B)
109
+ self._app_connect_event.set()
110
+
111
+ def _start_heartbeat(self):
112
+ def heartbeat():
113
+ if self.client and self.client.sock and self.client.sock.connected:
114
+ self._send_message(
115
+ {"type": "heartbeat", "clientId": self.client_id, "message": "200"},
116
+ update=False,
117
+ )
118
+ else:
119
+ logger.error("WebSocket not connected")
120
+
121
+ self.heartbeat_interval = threading.Timer(self.interval, heartbeat)
122
+ self.heartbeat_interval.start()
123
+
124
+ def _stop_heartbeat(self):
125
+ if self.heartbeat_interval:
126
+ self.heartbeat_interval.cancel()
127
+ self.heartbeat_interval = None
128
+ logger.info("Heartbeat stopped")
129
+
130
+ def _handle_message(self, data: str):
131
+ try:
132
+ message = json.loads(data)
133
+
134
+ if message.get("type") == "bind":
135
+ self.client_id = message["clientId"]
136
+ self._start_heartbeat()
137
+ self._update_connects(message)
138
+ self._bind_event.set()
139
+
140
+ logger.info(f"Received message: {message}")
141
+ except Exception as _:
142
+ logger.info(f"Received raw message: {data}")
143
+
144
+ def _send_message(self, message: dict, update=True):
145
+ if self.client and self.client.sock and self.client.sock.connected:
146
+ if update:
147
+ dict.update(
148
+ message, {"clientId": self.client_id, "targetId": self.target_id}
149
+ )
150
+ self.client.send(json.dumps(message))
151
+ logger.info(f"Sent message: {json.dumps(message)}")
152
+ else:
153
+ logger.error("WebSocket not connected")
154
+
155
+ def close(self):
156
+ if self.client:
157
+ self.client.close()
158
+ logger.info("WebSocket closed")
159
+ self._stop_heartbeat()
160
+ self._app_connect_event.clear()
161
+ self._bind_event.clear()
162
+
163
+ @staticmethod
164
+ def _wave2hex(data):
165
+ return ["".join(format(num, "02X") for num in sum(item, [])) for item in data]
166
+
167
+ def send_wave_message(self, wave, time: int, channel: Channel = None):
168
+ if channel == 1:
169
+ channel = "A"
170
+ elif channel == 2:
171
+ channel = "B"
172
+ elif channel == 3:
173
+ channel = "BOTH"
174
+
175
+ def _create_wave_message(channel: str, wave, time: int) -> dict:
176
+ return {
177
+ "type": MessageType.CLIENT_MSG,
178
+ "channel": channel,
179
+ "message": f"{channel}:{json.dumps(self._wave2hex(wave))}",
180
+ "time": time,
181
+ }
182
+
183
+ # type : clientMsg 固定不变
184
+ # message : A通道波形数据(16进制HEX数组json,具体见上面的协议说明)
185
+ # message2 : B通道波形数据(16进制HEX数组json,具体见上面的协议说明)
186
+ # time1 : A通道波形数据持续发送时长
187
+ # time2 : B通道波形数据持续发送时长
188
+ if channel == "BOTH":
189
+ for ch in ["A", "B"]:
190
+ message = _create_wave_message(ch, wave, time)
191
+ self._send_message(message)
192
+ else:
193
+ message = _create_wave_message(channel, wave, time)
194
+ self._send_message(message)
195
+
196
+ def clear_wave(self, channel: Channel):
197
+ if channel == Channel.A:
198
+ self._send_message(
199
+ {
200
+ "type": "msg",
201
+ "message": "clear-1",
202
+ }
203
+ )
204
+ elif channel == Channel.B:
205
+ self._send_message(
206
+ {
207
+ "type": "msg",
208
+ "message": "clear-2",
209
+ }
210
+ )
211
+ elif channel == Channel.BOTH:
212
+ self._send_message(
213
+ {
214
+ "type": "msg",
215
+ "message": "clear-1",
216
+ }
217
+ )
218
+ self._send_message(
219
+ {
220
+ "type": "msg",
221
+ "message": "clear-2",
222
+ }
223
+ )
224
+ else:
225
+ logger.error(f"Invalid channel: {channel}")
226
+
227
+ def clear_all_wave(self):
228
+ # type : msg 固定不变
229
+ # message: clear-1 -> 清除A通道波形队列; clear-2 -> 清除B通道波形队列
230
+ self._send_message(
231
+ {
232
+ "type": "msg",
233
+ "message": "clear-1",
234
+ }
235
+ )
236
+ self._send_message(
237
+ {
238
+ "type": "msg",
239
+ "message": "clear-2",
240
+ }
241
+ )
242
+ logger.info("Cleared all waves")
243
+ return True
244
+
245
+ def set_strength(
246
+ self, channel: Channel, type_id: StrengthType, strength: int
247
+ ) -> None:
248
+ # type : 1 -> 通道强度减少; 2 -> 通道强度增加; 3 -> 通道强度归零 ;4 -> 通道强度指定为某个值
249
+ # strength: 强度值变化量/指定强度值(当type为1或2时,该值会被强制设置为1)
250
+ # message: 'set channel' 固定不变
251
+ if type_id in [
252
+ StrengthType.DECREASE,
253
+ StrengthType.INCREASE,
254
+ StrengthType.ZERO,
255
+ ]:
256
+ # 當type為DECREASE或INCREASE時,強度值強制設為1
257
+ if type_id in [StrengthType.DECREASE, StrengthType.INCREASE]:
258
+ strength = 1
259
+
260
+ if channel == Channel.BOTH:
261
+ self._send_message(
262
+ {
263
+ "type": type_id,
264
+ "channel": Channel.A,
265
+ "strength": strength,
266
+ "message": MessageType.SET_CHANNEL,
267
+ }
268
+ )
269
+ self._send_message(
270
+ {
271
+ "type": type_id,
272
+ "channel": Channel.B,
273
+ "strength": strength,
274
+ "message": MessageType.SET_CHANNEL,
275
+ }
276
+ )
277
+ else:
278
+ self._send_message(
279
+ {
280
+ "type": type_id,
281
+ "channel": channel,
282
+ "strength": strength,
283
+ "message": MessageType.SET_CHANNEL,
284
+ }
285
+ )
286
+
287
+ elif type_id == StrengthType.SPECIFIC:
288
+ if channel == Channel.BOTH:
289
+ self.strength.A = strength
290
+ self.strength.B = strength
291
+ self._send_message(
292
+ {
293
+ "type": type_id,
294
+ "message": f"strength-{Channel.A}+{StrengthMode.SPECIFIC}+{self.strength.A}",
295
+ }
296
+ )
297
+ self._send_message(
298
+ {
299
+ "type": type_id,
300
+ "message": f"strength-{Channel.B}+{StrengthMode.SPECIFIC}+{self.strength.B}",
301
+ }
302
+ )
303
+ else:
304
+ if channel == Channel.A:
305
+ self.strength.A = strength
306
+ self._send_message(
307
+ {
308
+ "type": type_id,
309
+ "message": f"strength-{channel}+{StrengthMode.SPECIFIC}+{self.strength.A}",
310
+ }
311
+ )
312
+ elif channel == Channel.B:
313
+ self.strength.B = strength
314
+ self._send_message(
315
+ {
316
+ "type": type_id,
317
+ "message": f"strength-{channel}+{StrengthMode.SPECIFIC}+{self.strength.B}",
318
+ }
319
+ )
320
+
321
+ else:
322
+ logger.error(f"Invalid type id: {type_id}")
323
+ return
324
+
325
+
326
+ if __name__ == "__main__":
327
+
328
+ async def main():
329
+ client = dglabv3()
330
+
331
+ try:
332
+ await client.connect_and_wait()
333
+ qr_code = client.generate_qrcode_text()
334
+ print(qr_code)
335
+
336
+ except Exception as e:
337
+ logger.error(f"Error: {e}")
338
+ client.close()
339
+
340
+ asyncio.run(main())
dglabv3/dtype.py ADDED
@@ -0,0 +1,72 @@
1
+ from enum import Enum, IntEnum
2
+ from typing import Final
3
+ from dataclasses import dataclass, field
4
+
5
+ __all__ = ["ChannelStrength", "StrengthType", "StrengthMode", "MessageType", "Channel"]
6
+
7
+
8
+ class Channel(IntEnum):
9
+ A = 1
10
+ B = 2
11
+ BOTH = 3
12
+
13
+
14
+ MAX_STRENGTH: Final[int] = 200
15
+ MIN_STRENGTH: Final[int] = 0
16
+
17
+
18
+ @dataclass
19
+ class ChannelStrength:
20
+ _A: int = field(default=0, init=False)
21
+ _B: int = field(default=0, init=False)
22
+
23
+ def __post_init__(self):
24
+ self.A = self._A
25
+ self.B = self._B
26
+
27
+ @property
28
+ def A(self):
29
+ return self._A
30
+
31
+ @A.setter
32
+ def A(self, value):
33
+ if value > MAX_STRENGTH:
34
+ raise ValueError("stronger A cannot be greater than 200")
35
+ if value < MIN_STRENGTH:
36
+ raise ValueError("stronger A cannot be less than 0")
37
+ self._A = value
38
+
39
+ @property
40
+ def B(self):
41
+ return self._B
42
+
43
+ @B.setter
44
+ def B(self, value):
45
+ if value > MAX_STRENGTH:
46
+ raise ValueError("stronger B cannot be greater than 200")
47
+ if value < MIN_STRENGTH:
48
+ raise ValueError("stronger B cannot be less than 0")
49
+ self._B = value
50
+
51
+
52
+ # 強度調整類型
53
+ class StrengthType(IntEnum):
54
+ DECREASE = 1 # 通道強度減少
55
+ INCREASE = 2 # 通道強度增加
56
+ ZERO = 3 # 通道強度歸零
57
+ SPECIFIC = 4 # 通道強度指定為某個值
58
+
59
+
60
+ # 強度變化模式(用於 type 4)
61
+ class StrengthMode(IntEnum):
62
+ DECREASE = 0 # 通道強度減少
63
+ INCREASE = 1 # 通道強度增加
64
+ SPECIFIC = 2 # 通道強度變化為指定數值
65
+
66
+
67
+ class MessageType(str, Enum):
68
+ SET_CHANNEL = "set channel"
69
+ HEARTBEAT = "heartbeat"
70
+ BIND = "bind"
71
+ CLIENT_MSG = "clientMsg"
72
+ MSG = "msg"
dglabv3/waves.py ADDED
@@ -0,0 +1,228 @@
1
+ import random
2
+
3
+
4
+ class Pulse:
5
+ def __init__(self):
6
+ self.breath = PULSES["呼吸"]
7
+ self.tide = PULSES["潮汐"]
8
+ self.combo = PULSES["連擊"]
9
+ self.quick_pinch = PULSES["快速按捏"]
10
+ self.strong = PULSES["按捏增強"]
11
+ self.heartbeat = PULSES["心跳節奏"]
12
+ self.compress = PULSES["壓縮"]
13
+ self.rhythm = PULSES["節奏步伐"]
14
+ self.friction = PULSES["顆粒摩擦"]
15
+ self.bounce = PULSES["漸變彈跳"]
16
+ self.wave = PULSES["波浪"]
17
+ self.rain = PULSES["雨水冲刷"]
18
+ self.speed = PULSES["變速敲擊"]
19
+ self.signal = PULSES["信號燈"]
20
+ self.tease1 = PULSES["挑逗1"]
21
+ self.tease2 = PULSES["挑逗2"]
22
+
23
+ def random_pulse(self):
24
+ return PULSES[random.choice(ALL_PULSES)]
25
+
26
+
27
+ ALL_PULSES = [
28
+ "呼吸",
29
+ "潮汐",
30
+ "連擊",
31
+ "快速按捏",
32
+ "按捏增強",
33
+ "心跳節奏",
34
+ "壓縮",
35
+ "節奏步伐",
36
+ "顆粒摩擦",
37
+ "漸變彈跳",
38
+ "波浪",
39
+ "雨水冲刷",
40
+ "變速敲擊",
41
+ "信號燈",
42
+ "挑逗1",
43
+ "挑逗2",
44
+ ]
45
+
46
+ PULSES = {
47
+ "呼吸": [
48
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
49
+ [[10, 10, 10, 10], [0, 5, 10, 20]],
50
+ [[10, 10, 10, 10], [20, 25, 30, 40]],
51
+ [[10, 10, 10, 10], [40, 45, 50, 60]],
52
+ [[10, 10, 10, 10], [60, 65, 70, 80]],
53
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
54
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
55
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
56
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
57
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
58
+ ],
59
+ "潮汐": [
60
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
61
+ [[10, 10, 10, 10], [0, 4, 8, 17]],
62
+ [[10, 10, 10, 10], [17, 21, 25, 33]],
63
+ [[10, 10, 10, 10], [50, 50, 50, 50]],
64
+ [[10, 10, 10, 10], [50, 54, 58, 67]],
65
+ [[10, 10, 10, 10], [67, 71, 75, 83]],
66
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
67
+ [[10, 10, 10, 10], [100, 98, 96, 92]],
68
+ [[10, 10, 10, 10], [92, 90, 88, 84]],
69
+ [[10, 10, 10, 10], [84, 82, 80, 76]],
70
+ [[10, 10, 10, 10], [68, 68, 68, 68]],
71
+ ],
72
+ "連擊": [
73
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
74
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
75
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
76
+ [[10, 10, 10, 10], [100, 92, 84, 67]],
77
+ [[10, 10, 10, 10], [67, 58, 50, 33]],
78
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
79
+ [[10, 10, 10, 10], [0, 0, 0, 1]],
80
+ [[10, 10, 10, 10], [2, 2, 2, 2]],
81
+ ],
82
+ "快速按捏": [
83
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
84
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
85
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
86
+ ],
87
+ "按捏增強": [
88
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
89
+ [[10, 10, 10, 10], [29, 29, 29, 29]],
90
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
91
+ [[10, 10, 10, 10], [52, 52, 52, 52]],
92
+ [[10, 10, 10, 10], [2, 2, 2, 2]],
93
+ [[10, 10, 10, 10], [73, 73, 73, 73]],
94
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
95
+ [[10, 10, 10, 10], [87, 87, 87, 87]],
96
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
97
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
98
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
99
+ ],
100
+ "心跳節奏": [
101
+ [[110, 110, 110, 110], [100, 100, 100, 100]],
102
+ [[110, 110, 110, 110], [100, 100, 100, 100]],
103
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
104
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
105
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
106
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
107
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
108
+ [[10, 10, 10, 10], [75, 75, 75, 75]],
109
+ [[10, 10, 10, 10], [75, 77, 79, 83]],
110
+ [[10, 10, 10, 10], [83, 85, 88, 92]],
111
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
112
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
113
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
114
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
115
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
116
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
117
+ ],
118
+ "壓縮": [
119
+ [[25, 25, 24, 24], [100, 100, 100, 100]],
120
+ [[24, 23, 23, 23], [100, 100, 100, 100]],
121
+ [[22, 22, 22, 21], [100, 100, 100, 100]],
122
+ [[21, 21, 20, 20], [100, 100, 100, 100]],
123
+ [[20, 19, 19, 19], [100, 100, 100, 100]],
124
+ [[18, 18, 18, 17], [100, 100, 100, 100]],
125
+ [[17, 16, 16, 16], [100, 100, 100, 100]],
126
+ [[15, 15, 15, 14], [100, 100, 100, 100]],
127
+ [[14, 14, 13, 13], [100, 100, 100, 100]],
128
+ [[13, 12, 12, 12], [100, 100, 100, 100]],
129
+ [[11, 11, 11, 10], [100, 100, 100, 100]],
130
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
131
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
132
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
133
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
134
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
135
+ ],
136
+ "節奏步伐": [
137
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
138
+ [[10, 10, 10, 10], [50, 50, 50, 50]],
139
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
140
+ [[10, 10, 10, 10], [100, 100, 100, 100]],
141
+ [[10, 10, 10, 10], [50, 50, 50, 50]],
142
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
143
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
144
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
145
+ ],
146
+ "顆粒摩擦": [
147
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
148
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
149
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
150
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
151
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
152
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
153
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
154
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
155
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
156
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
157
+ ],
158
+ "漸變彈跳": [
159
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
160
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
161
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
162
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
163
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
164
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
165
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
166
+ [[50, 50, 50, 50], [0, 0, 0, 0]],
167
+ ],
168
+ "波浪": [
169
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
170
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
171
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
172
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
173
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
174
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
175
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
176
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
177
+ ],
178
+ "雨水冲刷": [
179
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
180
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
181
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
182
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
183
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
184
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
185
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
186
+ [[0, 0, 0, 0], [0, 0, 0, 0]],
187
+ ],
188
+ "變速敲擊": [
189
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
190
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
191
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
192
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
193
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
194
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
195
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
196
+ [[100, 100, 100, 100], [0, 0, 0, 0]],
197
+ ],
198
+ "信號燈": [
199
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
200
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
201
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
202
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
203
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
204
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
205
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
206
+ [[10, 10, 10, 10], [0, 0, 0, 0]],
207
+ ],
208
+ "挑逗1": [
209
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
210
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
211
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
212
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
213
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
214
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
215
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
216
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
217
+ ],
218
+ "挑逗2": [
219
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
220
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
221
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
222
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
223
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
224
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
225
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
226
+ [[20, 20, 20, 20], [0, 0, 0, 0]],
227
+ ],
228
+ }