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 +3 -0
- dglabv3/dglab.py +340 -0
- dglabv3/dtype.py +72 -0
- dglabv3/waves.py +228 -0
- dglabv3-0.1.dev6.dist-info/LICENSE +674 -0
- dglabv3-0.1.dev6.dist-info/METADATA +689 -0
- dglabv3-0.1.dev6.dist-info/RECORD +9 -0
- dglabv3-0.1.dev6.dist-info/WHEEL +5 -0
- dglabv3-0.1.dev6.dist-info/top_level.txt +1 -0
dglabv3/__init__.py
ADDED
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
|
+
}
|