[Enhance] Link Play 2.0 e.t.c.

- For Arcaea 5.10.1(c)
- Add support for Link Play 2.0.
- New partners "Luna & Ilot" and "Eto & Hoppe"
- Add support for the skill of "Eto & Hoppe".
- Add support for refreshing ratings of Recent 30 via API and webpage.

Note: This is a bug testing version.
This commit is contained in:
Lost-MSth
2024-09-06 22:43:38 +08:00
parent 59422f96b5
commit 014531f3f1
21 changed files with 1184 additions and 253 deletions

View File

@@ -1,14 +1,27 @@
import logging
import time
from .udp_class import Room, bi
from .config import Config
from .udp_class import Room, bi
from .udp_sender import CommandSender
class CommandParser:
route = [None, 'command_01', 'command_02', 'command_03', 'command_04', 'command_05',
'command_06', 'command_07', 'command_08', 'command_09', 'command_0a', 'command_0b']
route = {
0x01: 'command_01',
0x02: 'command_02',
0x03: 'command_03',
0x04: 'command_04',
0x06: 'command_06',
0x07: 'command_07',
0x08: 'command_08',
0x09: 'command_09',
0x0a: 'command_0a',
0x0b: 'command_0b',
0x20: 'command_20',
0x22: 'command_22',
0x23: 'command_23',
}
def __init__(self, room: Room, player_index: int = 0) -> None:
self.room = room
@@ -31,7 +44,7 @@ class CommandParser:
re.append(self.room.command_queue[i])
if self.room.players[self.player_index].extra_command_queue:
re += self.room.players[self.player_index].extra_command_queue
re += self.room.players[self.player_index].extra_command_queue[-12:]
self.room.players[self.player_index].extra_command_queue = []
if r:
@@ -52,10 +65,14 @@ class CommandParser:
self.room.command_queue.append(self.s.command_10())
def command_02(self):
# 房主选歌
if self.room.round_mode == 3:
logging.warning('Error: round_mode == 3 in command 02')
return None
self.s.random_code = self.command[16:24]
song_idx = bi(self.command[24:26])
flag = 2
flag = 5
if self.room.state == 2:
flag = 0
self.room.state = 3
@@ -69,10 +86,17 @@ class CommandParser:
# 尝试进入结算
self.s.random_code = self.command[16:24]
player = self.room.players[self.player_index]
player.score = bi(self.command[24:28])
player.cleartype = self.command[28]
player.difficulty = self.command[29]
player.best_score_flag = self.command[30]
player.score.score = bi(self.command[24:28])
player.score.cleartype = self.command[28]
player.score.difficulty = self.command[29]
player.score.best_score_flag = self.command[30]
player.score.shiny_perfect_count = bi(self.command[31:33])
player.score.perfect_count = bi(self.command[33:35])
player.score.near_count = bi(self.command[35:37])
player.score.miss_count = bi(self.command[37:39])
player.score.early_count = bi(self.command[39:41])
player.score.late_count = bi(self.command[41:43])
player.score.healthy = bi(self.command[43:47])
player.finish_flag = 1
player.last_timestamp -= Config.COMMAND_INTERVAL
self.room.last_song_idx = self.room.song_idx
@@ -94,19 +118,16 @@ class CommandParser:
flag = 1
self.room.delete_player(i)
self.room.command_queue.append(self.s.command_12(i))
self.room.update_song_unlock()
self.room.command_queue.append(self.s.command_14())
break
return [self.s.command_0d(flag)]
def command_05(self):
pass
def command_06(self):
self.s.random_code = self.command[16:24]
self.room.state = 1
self.room.song_idx = 0xffff
self.room.voting_clear()
self.room.command_queue.append(self.s.command_13())
@@ -117,13 +138,17 @@ class CommandParser:
self.room.command_queue.append(self.s.command_14())
# 07 可能需要一个 0d 响应code = 0x0b
def command_08(self):
self.room.round_switch = bi(self.command[24:25])
self.s.random_code = self.command[16:24]
self.room.command_queue.append(self.s.command_13())
# 可能弃用
logging.warning('Command 08 is outdated')
pass
# self.room.round_mode = bi(self.command[24:25])
# self.s.random_code = self.command[16:24]
# self.room.command_queue.append(self.s.command_13())
def command_09(self):
re = []
self.s.random_code = self.command[16:24]
player = self.room.players[self.player_index]
@@ -133,133 +158,166 @@ class CommandParser:
self.room.update_song_unlock()
player.start_command_num = self.room.command_queue_length
self.room.command_queue.append(self.s.command_15())
else:
if self.s.timestamp - player.last_timestamp >= Config.COMMAND_INTERVAL:
re.append(self.s.command_0c())
player.last_timestamp = self.s.timestamp
return None
# 离线判断
flag_13, player_index_list = self.room.check_player_online(
self.s.timestamp)
for i in player_index_list:
self.room.command_queue.append(self.s.command_12(i))
flag_0c = False
flag_11 = False
flag_12 = False
if self.s.timestamp - player.last_timestamp >= Config.COMMAND_INTERVAL:
flag_0c = True
player.last_timestamp = self.s.timestamp
if player.online == 0:
flag_12 = True
player.online = 1
# 离线判断
flag_13, player_index_list = self.room.check_player_online(
self.s.timestamp)
for i in player_index_list:
self.room.command_queue.append(self.s.command_12(i))
if self.room.is_ready(1, 1):
flag_13 = True
self.room.state = 2
flag_11 = False
flag_12 = False
if player.player_state != self.command[32]:
flag_12 = True
player.player_state = self.command[32]
if player.online == 0:
flag_12 = True
player.online = 1
if player.difficulty != self.command[33] and player.player_state != 5 and player.player_state != 6 and player.player_state != 7 and player.player_state != 8:
flag_12 = True
player.difficulty = self.command[33]
if self.room.state in (1, 2) and player.player_state == 8:
# 还在结算给踢了
# 冗余,为了保险
self.room.delete_player(self.player_index)
self.room.command_queue.append(
self.s.command_12(self.player_index))
self.room.command_queue.append(self.s.command_14())
if player.cleartype != self.command[34] and player.player_state != 7 and player.player_state != 8:
flag_12 = True
player.cleartype = self.command[34]
if self.room.is_ready(1, 1) and ((self.room.player_num > 1 and not self.room.is_public) or (self.room.is_public and self.room.player_num == 4)):
flag_13 = True
self.room.state = 2
if player.download_percent != self.command[35]:
flag_12 = True
player.download_percent = self.command[35]
if self.room.state == 1 and self.room.is_public and self.room.player_num > 1 and self.room.should_next_state:
flag_0c = True
flag_13 = True
self.room.state = 2
if player.character_id != self.command[36]:
flag_12 = True
player.character_id = self.command[36]
if self.room.state in (2, 3) and self.room.player_num < 2:
flag_13 = True
self.room.state = 1
if player.is_uncapped != self.command[37]:
flag_12 = True
player.is_uncapped = self.command[37]
if self.room.state == 2 and self.room.should_next_state:
flag_0c = True
self.room.state = 3
flag_13 = True
if self.room.round_mode == 3:
self.room.make_voting()
else:
self.room.random_song()
if self.room.state == 3 and player.score != bi(self.command[24:28]):
flag_12 = True
player.score = bi(self.command[24:28])
if player.player_state != self.command[32]:
flag_12 = True
player.player_state = self.command[32]
if self.room.is_ready(3, 4):
flag_13 = True
self.room.countdown = Config.COUNTDOWM_TIME
self.room.timestamp = round(time.time() * 1000)
self.room.state = 4
if self.room.round_switch == 1:
# 将换房主时间提前到此刻
self.room.make_round()
if player.score.difficulty != self.command[33] and player.player_state not in (5, 6, 7, 8):
flag_12 = True
player.score.difficulty = self.command[33]
logging.info(f'Room `{self.room.room_code}` starts playing')
if player.score.cleartype != self.command[34] and player.player_state != 7 and player.player_state != 8:
flag_12 = True
player.score.cleartype = self.command[34]
if self.room.state in (4, 5, 6):
timestamp = round(time.time() * 1000)
self.room.countdown -= timestamp - self.room.timestamp
self.room.timestamp = timestamp
if self.room.state == 4 and self.room.countdown <= 0:
# 此处不清楚
self.room.state = 5
self.room.countdown = 5999
flag_11 = True
flag_13 = True
if player.download_percent != self.command[35]:
flag_12 = True
player.download_percent = self.command[35]
if self.room.state == 5 and self.room.is_ready(5, 6):
self.room.state = 6
flag_13 = True
if player.character_id != self.command[36]:
flag_12 = True
player.character_id = self.command[36]
if self.room.state == 5 and self.room.is_ready(5, 7):
self.room.state = 7
self.room.countdown = 0xffffffff
flag_13 = True
if player.is_uncapped != self.command[37]:
flag_12 = True
player.is_uncapped = self.command[37]
if self.room.state == 5 and self.room.countdown <= 0:
print('我怎么知道这是啥')
if self.room.state == 3 and player.score.score != bi(self.command[24:28]):
flag_12 = True
player.score.score = bi(self.command[24:28])
if self.room.state == 6 and self.room.countdown <= 0:
# 此处不清楚
self.room.state = 7
self.room.countdown = 0xffffffff
flag_13 = True
if self.room.is_ready(3, 4) or (self.room.state == 3 and self.room.should_next_state):
flag_13 = True
flag_0c = True
self.room.state = 4
self.room.countdown = self.room.countdown if self.room.countdown > 0 else 0
if self.room.round_mode == 2:
# 将换房主时间提前到此刻
self.room.make_round()
logging.info(f'Room `{self.room.room_code}` starts playing')
if self.room.state in (7, 8):
if player.timer < bi(self.command[28:32]) or bi(self.command[28:32]) == 0 and player.timer != 0:
player.last_timer = player.timer
player.last_score = player.score
player.timer = bi(self.command[28:32])
player.score = bi(self.command[24:28])
if player.timer != 0 or self.room.state != 8:
for i in self.room.players:
i.extra_command_queue.append(
self.s.command_0e(self.player_index))
if self.room.is_ready(8, 1):
flag_13 = True
self.room.state = 1
self.room.song_idx = 0xffff
for i in self.room.players:
i.timer = 0
i.score = 0
if self.room.is_finish():
# 有人退房导致的结算
self.room.make_finish()
flag_13 = True
if flag_11:
self.room.command_queue.append(self.s.command_11())
if flag_12:
if self.room.state == 4:
if player.download_percent != 0xff:
# 有人没下载完把他踢了!
self.room.delete_player(self.player_index)
self.room.command_queue.append(
self.s.command_12(self.player_index))
if flag_13:
self.room.command_queue.append(self.s.command_13())
self.room.command_queue.append(self.s.command_14())
return re
if self.room.should_next_state:
self.room.state = 5
flag_11 = True
flag_13 = True
if self.room.state == 5:
flag_13 = True
if self.room.is_ready(5, 6):
self.room.state = 6
if self.room.is_ready(5, 7):
self.room.state = 7
if self.room.state in (5, 6) and self.room.should_next_state:
# 此处不清楚
self.room.state = 7
flag_13 = True
if self.room.state in (7, 8):
player_now_timer = bi(self.command[28:32])
if player.score.timer < player_now_timer or player_now_timer == 0 and player.score.timer != 0:
player.last_score.timer = player.score.timer
player.last_score.score = player.score.score
player.score.timer = player_now_timer
player.score.score = bi(self.command[24:28])
if player.score.timer != 0 or self.room.state != 8:
for i in self.room.players:
i.extra_command_queue.append(
self.s.command_0e(self.player_index))
if self.room.is_ready(8, 1):
flag_13 = True
self.room.state = 1
self.room.song_idx = 0xffff
if self.room.state == 8 and self.room.should_next_state:
flag_0c = True
flag_13 = True
self.room.state = 1
self.room.song_idx = 0xffff
if self.room.state in (1, 2) and player.player_state == 8:
# 还在结算给踢了
self.room.delete_player(self.player_index)
self.room.command_queue.append(
self.s.command_12(self.player_index))
self.room.command_queue.append(self.s.command_14())
if self.room.is_finish():
# 有人退房导致的结算
self.room.make_finish()
flag_13 = True
if flag_11:
self.room.command_queue.append(self.s.command_11())
if flag_12:
self.room.command_queue.append(
self.s.command_12(self.player_index))
if flag_13:
self.room.command_queue.append(self.s.command_13())
if flag_0c:
return [self.s.command_0c()]
def command_0a(self):
# 退出房间
@@ -267,9 +325,6 @@ class CommandParser:
self.room.command_queue.append(self.s.command_12(self.player_index))
if self.room.state in (2, 3):
self.room.state = 1
self.room.song_idx = 0xffff
# self.room.command_queue.append(self.s.command_11())
self.room.command_queue.append(self.s.command_13())
self.room.command_queue.append(self.s.command_14())
@@ -281,3 +336,45 @@ class CommandParser:
if self.player_index != i and self.room.players[i].online == 1:
self.room.players[i].extra_command_queue.append(
self.s.command_0f(self.player_index, song_idx))
def command_20(self):
# 表情
sticker_id = bi(self.command[16:18])
for i in range(4):
if self.player_index != i and self.room.players[i].online == 1:
self.room.players[i].extra_command_queue.append(
self.s.command_21(self.player_index, sticker_id))
def command_22(self):
# 房间设置,懒得判断房主
self.s.random_code = self.command[16:24]
self.room.is_public = self.command[25]
if self.room.is_public == 0:
self.room.round_mode = self.command[24]
self.room.timed_mode = self.command[26]
else:
self.room.round_mode = 3
self.room.timed_mode = 1
self.room.state = 1
self.room.command_queue.append(self.s.command_11())
self.room.command_queue.append(self.s.command_13())
return [self.s.command_0d(1)]
def command_23(self):
# 歌曲投票
self.s.random_code = self.command[16:24]
if self.room.player_num < 2:
return [self.s.command_0d(6)]
if self.room.state != 2:
return [self.s.command_0d(5)]
player = self.room.players[self.player_index]
player.voting = bi(self.command[24:26])
logging.info(
f'Player `{player.name}` votes for song `{player.voting}`')
self.room.command_queue.append(self.s.command_12(self.player_index))
if self.room.is_all_player_voted:
self.room.make_voting()
self.room.command_queue.append(self.s.command_13())
return [self.s.command_0d(1)]