mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2025-12-14 08:06:23 +08:00
[Enhance] Link Play Rooms info & API for that
- Add an HTTP API endpoint for getting the information of rooms and players in Link Play
This commit is contained in:
@@ -1,15 +1,10 @@
|
||||
from flask import Blueprint
|
||||
|
||||
from . import (users, songs, token, system, items,
|
||||
purchases, presents, redeems, characters)
|
||||
purchases, presents, redeems, characters, multiplay)
|
||||
|
||||
bp = Blueprint('api', __name__, url_prefix='/api/v1')
|
||||
bp.register_blueprint(users.bp)
|
||||
bp.register_blueprint(songs.bp)
|
||||
bp.register_blueprint(token.bp)
|
||||
bp.register_blueprint(system.bp)
|
||||
bp.register_blueprint(items.bp)
|
||||
bp.register_blueprint(purchases.bp)
|
||||
bp.register_blueprint(presents.bp)
|
||||
bp.register_blueprint(redeems.bp)
|
||||
bp.register_blueprint(characters.bp)
|
||||
l = [users, songs, token, system, items, purchases,
|
||||
presents, redeems, characters, multiplay]
|
||||
for i in l:
|
||||
bp.register_blueprint(i.bp)
|
||||
|
||||
21
latest version/api/multiplay.py
Normal file
21
latest version/api/multiplay.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from flask import Blueprint, request
|
||||
|
||||
from core.linkplay import RemoteMultiPlayer
|
||||
|
||||
from .api_auth import api_try, request_json_handle, role_required
|
||||
from .api_code import success_return
|
||||
|
||||
|
||||
bp = Blueprint('multiplay', __name__, url_prefix='/multiplay')
|
||||
|
||||
|
||||
@bp.route('/rooms', methods=['GET'])
|
||||
@role_required(request, ['select'])
|
||||
@request_json_handle(request, optional_keys=['offset', 'limit'])
|
||||
@api_try
|
||||
def rooms_get(data, user):
|
||||
'''获取房间列表'''
|
||||
|
||||
r = RemoteMultiPlayer().get_rooms(offset=data.get(
|
||||
'offset', 0), limit=data.get('limit', 100))
|
||||
return success_return(r)
|
||||
@@ -138,35 +138,6 @@ class RemoteMultiPlayer:
|
||||
|
||||
return self.data_recv
|
||||
|
||||
# if self.data_recv[0] != '0':
|
||||
# code = int(self.data_recv[0])
|
||||
# raise ArcError(f'Link Play error code: {code}', code, status=400)
|
||||
|
||||
# @staticmethod
|
||||
# def tcp(data: str) -> str:
|
||||
# with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
# sock.connect((Constant.LINKPLAY_HOST,
|
||||
# Constant.LINKPLAY_TCP_PORT))
|
||||
# send_data =
|
||||
# sock.sendall(bytes(data + "\n", "utf-8"))
|
||||
# try:
|
||||
# received = str(sock.recv(1024), "utf-8").strip()
|
||||
# except socket.timeout as e:
|
||||
# raise Timeout(
|
||||
# 'Timeout when waiting for data from link play server.', status=400) from e
|
||||
# # print(received)
|
||||
# return received
|
||||
|
||||
# def data_swap(self, data: tuple) -> tuple:
|
||||
|
||||
# received = self.tcp(Constant.LINKPLAY_AUTHENTICATION +
|
||||
# '|' + '|'.join([str(x) for x in data]))
|
||||
|
||||
# self.data_recv = received.split('|')
|
||||
# if self.data_recv[0] != '0':
|
||||
# code = int(self.data_recv[0])
|
||||
# raise ArcError(f'Link Play error code: {code}', code, status=400)
|
||||
|
||||
def create_room(self, user: 'Player' = None) -> None:
|
||||
'''创建房间'''
|
||||
if user is not None:
|
||||
@@ -231,3 +202,15 @@ class RemoteMultiPlayer:
|
||||
self.room.song_unlock = b64decode(x['song_unlock'])
|
||||
self.user.key = b64decode(x['key'])
|
||||
self.user.player_id = int(x['player_id'])
|
||||
|
||||
def get_rooms(self, offset=0, limit=50) -> dict:
|
||||
'''获取房间列表'''
|
||||
self.data_swap({
|
||||
'endpoint': 'get_rooms',
|
||||
'data': {
|
||||
'offset': offset,
|
||||
'limit': limit
|
||||
}
|
||||
})
|
||||
|
||||
return self.data_recv['data']
|
||||
|
||||
@@ -91,6 +91,7 @@ class TCPRouter:
|
||||
'create_room',
|
||||
'join_room',
|
||||
'update_room',
|
||||
'get_rooms',
|
||||
}
|
||||
|
||||
def __init__(self, raw_data: 'dict | list'):
|
||||
@@ -115,7 +116,11 @@ class TCPRouter:
|
||||
self.clean_check()
|
||||
if self.endpoint not in self.router:
|
||||
return None
|
||||
r = getattr(self, self.endpoint)()
|
||||
try:
|
||||
r = getattr(self, self.endpoint)()
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return 999
|
||||
if isinstance(r, int):
|
||||
return {'code': r}
|
||||
return {
|
||||
@@ -257,3 +262,41 @@ class TCPRouter:
|
||||
'player_id': r['player_id'],
|
||||
'song_unlock': b64encode(room.song_unlock).decode('utf-8')
|
||||
}
|
||||
|
||||
def get_rooms(self) -> dict:
|
||||
# 获取房间列表与详细信息
|
||||
|
||||
offset = int(self.data.get('offset', 0))
|
||||
if offset < 0:
|
||||
offset = 0
|
||||
limit = min(int(self.data.get('limit', 100)), 100)
|
||||
if limit < 0:
|
||||
limit = 100
|
||||
|
||||
n = 0
|
||||
m = 0
|
||||
rooms = []
|
||||
f = False
|
||||
f2 = False
|
||||
for room in Store.room_id_dict.values():
|
||||
if room.player_num == 0:
|
||||
continue
|
||||
if m < offset:
|
||||
m += 1
|
||||
continue
|
||||
if f:
|
||||
# 处理刚好有 limit 个房间的情况
|
||||
f2 = True
|
||||
break
|
||||
n += 1
|
||||
rooms.append(room.to_dict())
|
||||
if n >= limit:
|
||||
f = True
|
||||
|
||||
return {
|
||||
'amount': n,
|
||||
'offset': offset,
|
||||
'limit': limit,
|
||||
'has_more': f2,
|
||||
'rooms': rooms
|
||||
}
|
||||
|
||||
@@ -49,6 +49,27 @@ class Player:
|
||||
def name(self) -> str:
|
||||
return self.player_name.decode('ascii').rstrip('\x00')
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
'multiplay_player_id': self.player_id,
|
||||
'name': self.name,
|
||||
'is_online': self.online == 1,
|
||||
'character_id': self.character_id,
|
||||
'is_uncapped': self.is_uncapped == 1,
|
||||
'last_song': {
|
||||
'difficulty': self.last_difficulty,
|
||||
'score': self.last_score,
|
||||
'cleartype': self.last_cleartype,
|
||||
},
|
||||
'song': {
|
||||
'difficulty': self.difficulty,
|
||||
'score': self.score,
|
||||
'cleartype': self.cleartype,
|
||||
},
|
||||
'player_state': self.player_state,
|
||||
'last_timestamp': self.last_timestamp,
|
||||
}
|
||||
|
||||
def set_player_name(self, player_name: str):
|
||||
self.player_name = player_name.encode('ascii')
|
||||
if len(self.player_name) > 16:
|
||||
@@ -80,6 +101,32 @@ class Room:
|
||||
|
||||
self.command_queue = []
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
p = [i.to_dict() for i in self.players if i.player_id != 0]
|
||||
for i in p:
|
||||
i['is_host'] = i['player_id'] == self.host_id
|
||||
return {
|
||||
'room_id': self.room_id,
|
||||
'room_code': self.room_code,
|
||||
'state': self.state,
|
||||
'song_idx': self.song_idx,
|
||||
'last_song_idx': self.last_song_idx if not self.is_playing else 0xffff,
|
||||
'host_id': self.host_id,
|
||||
'players': p,
|
||||
'round_switch': self.round_switch == 1,
|
||||
'last_timestamp': self.timestamp,
|
||||
'is_enterable': self.is_enterable,
|
||||
'is_playing': self.is_playing,
|
||||
}
|
||||
|
||||
@property
|
||||
def is_enterable(self) -> bool:
|
||||
return 0 < self.player_num < 4 and self.state == 2
|
||||
|
||||
@property
|
||||
def is_playing(self) -> bool:
|
||||
return self.state in (4, 5, 6, 7)
|
||||
|
||||
@property
|
||||
def command_queue_length(self) -> int:
|
||||
return len(self.command_queue)
|
||||
|
||||
Reference in New Issue
Block a user